欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

网络爬虫(三):简单使用scrapy

程序员文章站 2022-05-30 20:07:05
...

一.首先简单了解scrapy的架构
官方给出的解释:
网络爬虫(三):简单使用scrapy
Spiders: Spider是Scrapy用户编写用于分析response并提取item(即获取到的item)或额外跟进的URL的类。 每个spider负责处理一个特定(或一些)网站。

Item Pipeline: Item pipeline负责处理被spider提取出来的item。典型的处理有清理、 验证及持久化(例如存取到数据库中)。。

下载器中间件: 下载区中间件是在引擎及下载器之间的特定钩子(specific hook),处理Downloader传递给引擎的response。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能。 。

Spider中间件: Spider是在引擎及Spider之间的特定钩子(specific hook),处理spider的输入(response)和输出(items及requests)。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能。。

使用Scrapy爬取的过程如下:

1.引擎打开一个网站,找到处理该网站的Spider并向该spider请求第一个要爬取的URL(s)。
2.引擎从Spider中获取到第一个要爬取的URL并在调度器)以Request调度。
3.引擎向调度器请求下一个要爬取的URL。
4.调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求(request)方向)转发给下载器。
5.一旦页面下载完毕,下载器生成一个该页面的Response,并将其通过下载中间件(返回(response)方向)发送给引擎。
6.引擎从下载器中接收到Response并通过Spider中间件(输入方向)发送给Spider处理。
7.Spider处理Response并返回爬取到的Item及(跟进的)新的Request给引擎。
8.引擎将(Spider返回的)爬取到的Item给Item Pipeline,将(Spider返回的)Request给调度器。
9.(从第二步)重复直到调度器中没有更多地request,引擎关闭该网站。

二. 创建scrapy项目
首先我们需要创建一个Scrapy项目,打开命令行,进入到要储存代码的位置的根目录下,执行这条指令
scrapy startproject xxxxxx
这里需要输入你给该项目所取的名称。

执行了该指令之后会自动创建一个文件夹,名称为你对这个项目所取的名称。
其中包括
网络爬虫(三):简单使用scrapy
各文件作用:
scrapy.cfg: 项目的配置文件。
items.py: 项目中的item文件,定义了储存数据的字段名。
pipelines.py: 项目中的pipelines文件。
settings.py: 项目的设置文件。
spiders: 放置spider代码的目录。(主要在这里做文章)

三、实现爬爬爬!
选择所想爬取的网站,从命令行进去到该项目中运行

scrapy genspider quotes quotes.toscrape.com

注:在这里我以quotes.toscrape.com为例,quotes是name,name一般由网站名确定。

运行完成后会在spider文件夹中自动生成一个quotes.py文件
其代码为

import scrapy

class QuotesSpider (scrapy.Spider)
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com'
    start_urls = ['http://quotes.toscrape.com/']
    def parse(self,response):
        pass

对这个代码进行改动就可以进行简单的爬取,在这里以quotes.toscrape.com网站为例
所写代码为:

import scrapy
class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']

    def start_requests(self):#名称不要变
        for page  in range(20):
            url = 'http://quotes.toscrape.com/page/{}/'.format(page)
            yield scrapy.Request(url=url,callback=self.parse)
    def parse(self, response):#名称不要变
        page= response.url.split('/')[-2]
        #可以得到目前网址的页码
        file_name = 'quotes-{}.txt'.format(page)
        with open(file_name,'wb') as f:
            quotes = response.css('.quote')
            for index,quote in enumerate(quotes):
            #进行对应的排序 0 quote[0] quote[1] 
                text = quote.css('span.text::text').extract_first()
                #将内容以文本形式提取出来
                author = quote.css('small.author::text').extract_first()
                tags = quote.css('.tags .tag::text').extract()
                f.write("NO.{}".format(index+1).encode())
                #输出NO.1 2 3 4....
                f.write('\r\n'.encode())
                #换行
                f.write(text.encode())
                f.write("\r\n".encode())
                f.write("By{}".format(author).encode())
                f.write("\r\n".encode())
                tags_str = ''
                for tag in tags:
                    tags_str += tag + ","
                Tags = tag[0:-2]
                f.write(("Tags:"+tags).encode())
                #这样在结尾就不会有','
                f.write("\r\n".encode())
                f.write(("-"*20).encode())
                f.write("\r\n".encode())     

注:def start_requests(self),def parse(self, response)的名称和括号内的不要变,一但改变,无法从网站上爬取数据

text = quote.css('span.text::text').extract_first()

span.text是定位到了 具有span class =’text’属性的数据
.extract_first()=.extract()[0]可以提取出第一个节点

接下来就是最激动人心的时刻 /手动滑稽
在命令行进入到根目录下,运行这行代码:

scrapy crawl quotes

如果没有错误,静等片刻,打开到文件夹中,会生成.txt文件:
网络爬虫(三):简单使用scrapy
内容如下:
网络爬虫(三):简单使用scrapy

这样基本的一次使用scrapy算是大功告成。

四、进阶使用
可以进一步设置items.py文件,pipelines.py文件,将在网页中下载数据进行归类保存。
接下来实战爬取网易新闻的正文内容、时间、出版社等。
items.py
代码:

import scrapy
class NewsItem(scrapy.Item):
    news_thread = scrapy.Field() 
    news_title = scrapy.Field()
    news_url = scrapy.Field()
    news_time = scrapy.Field()
    news_source = scrapy.Field()
    source_url = scrapy.Field()
    news_text = scrapy.Field()

piplines.py
代码:

from scrapy.exporters import CsvItemExporter
class NewsPipeline(object):
    def __init__(self):
        self.file = open ('news_data.csv','wb')
        self.exporter = CsvItemExporter(self.file,encoding='gbk')
        self.exporter.start_exporting()
        #创建一个名称为news_data.csv的文件,并且将数据导入

    def process_item(self, item, spider):
        self.exporter.export_item(item)
        return item

    def close_spider(self,spider):
        self.exporter.finish_exporting()
        self.file.close()
        #定义结束传输

作用:将数据进行分类,并存入所创建的.csv文件中

主体代码:

这里的文件名由所创name决定
代码为:

import scrapy
from news.items import NewsItem
from scrapy.linkextractors import LinkExtractor
#链接提取器
from scrapy.spiders import CrawlSpider,Rule


class News163Spider(CrawlSpider):#类的继承
    name = 'news163'
    allowed_domains = ['news.163.com']
    start_urls = ['http://news.163.com/']
    rules = (
            Rule (LinkExtractor(allow=r"/18/09\d+/*"),
            callback ="parse_news",follow=True),
        )
            #如果满足allow=r"/18/09\d+/*(正则表达式) 把网站给parse-news

    def parse_news(self,response):
        item = NewsItem()#实例化操作,把item当成字典使用
        item['news_thread'] = response.url.strip().split('/')[-1][:-5]
        self.get_title(response,item)
        self.get_time(response,item)
        self.get_source(response,item)
        self.get_url(response,item)
        self.get_source_url(response,item)
        self.get_text(response,item)
        return item

    def get_title(self,response,item):
        title = response.css('title::text').extract()
        print('*'*20)
        if title:#判断是否为空
            print('title:{}'.format(title[0][:-5]))
            item['news_title']=title[0][:-5]
    def get_time(self,response,item):
        time = response.css('.post_time_source::text').extract()
        if time:
            print('time:{}'.format(time[0][:-5]))

            item['news_time'] = time[0][:-5]
    def get_source(self,response,item):
        source = response.css('#ne_article_source::text').extract()
        if source:
            print('source:{}'.format(source[0]))
            item['news_source'] = source[0]
    def get_source_url(self,response,item):
        source_url = response.css('#ne_article_source::attr(href)').extract()
        #attr是属性
        if source_url:
            print('source_url:{}'.format(source_url[0]))
            item['source_url'] = source_url[0]
    def get_text(self,response,item):
        text = response.css('#endText p::text').extract()
        if text:
            print('text:{}'.format(text))
            item['news_text'] = text
    def get_url(self,response,item):
        url = response.url
        if url:
            print('uews_url:{}'.format(url))
            item['news_url']=url            

运行后就可得到整理好的一个csv文件。

有很多不足挖坑待填。