爬虫框架Scrapy 之(二) --- scrapy文件介绍

框架介绍

文件分类

  1. 核心部分: 引擎、下载器、调度器
  2. 自定义部分: spider(自己建的爬虫文件)、管道(pipelines.py)

目录结构

    firstSpider
        firstSpider
            spiders          # 爬虫目录(写代码位置)负责存放继承自scrapy的爬虫类
                __init__.py
                budejie.py   # 自己建的爬虫文件,以后的爬虫代码写在这里
            __init__.py
            items.py        # 定义数据结构地方,负责数据模型的建立,类似于实体类
            middlewares.py  # 自己定义中间件地方(了解) 
            pipelines.py    # 管道文件,负责对spider返回数据的处理
            settings.py     # 项目配置文件,负责对整个爬虫的配置
        scrapy.cfg      # 基础配置

文件功能

  • spiders/budejie.py代码分析:spiders目录下的budejie.py为主要的爬虫代码,包括了对页面的请求以及页面的处理

 需要注意:

  爬取页面时,返回的是这个页面的信息,但是这时候需要的是获取每个文章的地址继续访问,

  就要用到了yield Request()这种用法,可以把获取到文章的url地址继续传递进来再次进行请求。

  scrapy提供了response.css这种的css选择器以及response.xpath的xpath选择器方法,我们可以根据自己的需求获取我们想要的字段信息

  • items.py代码分析:items.py里存放的是我们要爬取数据的字段信息
  • pipelines.py代码分析:pipeline主要是对spiders中爬虫的返回的数据的处理,可以让写入到数据库,也可以让写入到文件。可以定义各种我们需要的pipeline,不同的pipeline是有一定的顺序的,需要的设置是在settings配置文件中,后面的数字表示的是优先级,数字越小优先级越高。
  • settings.py代码分析:项目配置文件,负责对整个爬虫的配置
class ArticleSpider(scrapy.Spider):
    name = "Article"
    allowed_domains = ["blog.jobbole.com"]
    start_urls = ['http://blog.jobbole.com/all-posts/']

    def parse(self, response):
        '''
        1.获取文章列表也中具体文章url,并交给scrapy进行下载后并进行解析
        2.获取下一页的url并交给scrapy进行下载,下载完成后,交给parse
        :param response:
        :return:
        '''
        #解析列表页中所有文章的url,并交给scrapy下载后进行解析
        post_nodes = response.css("#archive .floated-thumb .post-thumb a")
        for post_node in post_nodes:
            #image_url是图片的地址
            image_url = post_node.css("img::attr(src)").extract_first("")
            post_url = post_node.css("::attr(href)").extract_first("")
            #这里通过meta参数将图片的url传递进来,这里用parse.urljoin的好处是如果有域名我前面的response.url不生效
            # 如果没有就会把response.url和post_url做拼接
            yield Request(url=parse.urljoin(response.url,post_url),meta={"front_image_url":parse.urljoin(response.url,image_url)},callback=self.parse_detail)

        #提取下一页并交给scrapy下载
        next_url = response.css(".next.page-numbers::attr(href)").extract_first("")
        if next_url:
            yield Request(url=next_url,callback=self.parse)

    def parse_detail(self,response):
        '''
        获取文章的详细内容
        :param response:
        :return:
        '''
        article_item = JoBoleArticleItem()



        front_image_url = response.meta.get("front_image_url","")  #文章封面图地址
        title = response.xpath('//div[@class="entry-header"]/h1/text()').extract_first()


        create_date = response.xpath('//p[@class="entry-meta-hide-on-mobile"]/text()').extract()[0].strip().split()[0]

        tag_list = response.xpath('//p[@class="entry-meta-hide-on-mobile"]/a/text()').extract()
        tag_list = [element for element in tag_list if not element.strip().endswith("评论")]
        tag =",".join(tag_list)
        praise_nums = response.xpath('//span[contains(@class,"vote-post-up")]/h10/text()').extract()
        if len(praise_nums) == 0:
            praise_nums = 0
        else:
            praise_nums = int(praise_nums[0])
        fav_nums  = response.xpath('//span[contains(@class,"bookmark-btn")]/text()').extract()[0]
        match_re = re.match(".*(d+).*",fav_nums)
        if match_re:
            fav_nums = int(match_re.group(1))
        else:
            fav_nums = 0

        comment_nums =response.xpath("//a[@href='#article-comment']/span/text()").extract()[0]
        match_com = re.match(".*(d+).*",comment_nums)
        if match_com:
            comment_nums = int(match_com.group(1))
        else:
            comment_nums=0

        content = response.xpath('//div[@class="entry"]').extract()[0]


        article_item["url_object_id"] = get_md5(response.url) #这里对地址进行了md5变成定长
        article_item["title"] = title
        article_item["url"] = response.url
        try:
            create_date = datetime.datetime.strptime(create_date,'%Y/%m/%d').date()
        except Exception as e:
            create_date = datetime.datetime.now().date()

        article_item["create_date"] = create_date
        article_item["front_image_url"] = [front_image_url]
        article_item["praise_nums"] = int(praise_nums)
        article_item["fav_nums"] = fav_nums
        article_item["comment_nums"] = comment_nums
        article_item["tag"] = tag
        article_item['content'] = content

        yield article_item
爬虫代码
 1 # -*- coding: utf-8 -*-
 2 
 3 # Scrapy settings for MyFristScrapy project
 4 #
 5 # For simplicity, this file contains only settings considered important or
 6 # commonly used. You can find more settings consulting the documentation:
 7 #
 8 #     https://docs.scrapy.org/en/latest/topics/settings.html
 9 #     https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
10 #     https://docs.scrapy.org/en/latest/topics/spider-middleware.html
11 
12 BOT_NAME = 'MyFristScrapy'  # 爬虫项目名字
13 
14 SPIDER_MODULES = ['MyFristScrapy.spiders'] # 爬虫的模版
15 
16 NEWSPIDER_MODULE = 'MyFristScrapy.spiders' # 新爬虫模版
17 
18 
19 #通过在用户代理上标识您自己(和您的网站),负责任地爬行  # 设置user_agent
20 #USER_AGENT = 'MyFristScrapy (+http://www.yourdomain.com)'
21 
22 # Obey robots.txt rules     # robots协议是否遵守
23 ROBOTSTXT_OBEY = True
24 
25 # 配置由Scrapy执行的最大并发请求(默认值:16). # 链接数量
26 #CONCURRENT_REQUESTS = 32
27 
28 #为同一网站的请求配置延迟(默认值:0)     # 下载时延
29 #见https://docs.scrapy.org/en/latest/topics/settings.html # download-delay
30 #参见自动油门设置和文档
31 #DOWNLOAD_DELAY = 3
32 
33 # 下载延迟设定只适用于以下其中一项:
34 #CONCURRENT_REQUESTS_PER_DOMAIN = 16
35 #CONCURRENT_REQUESTS_PER_IP = 16
36 
37 # 禁用cookie(默认启用)
38 #COOKIES_ENABLED = False
39 
40 # 禁用Telnet控制台(默认启用)
41 #TELNETCONSOLE_ENABLED = False
42 
43 # 覆盖默认的请求头:
44 #DEFAULT_REQUEST_HEADERS = {
45 #   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
46 #   'Accept-Language': 'en',
47 #}
48 
49 # 启用或禁用爬行器中间件
50 # See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
51 #SPIDER_MIDDLEWARES = {
52 #    'MyFristScrapy.middlewares.MyfristscrapySpiderMiddleware': 543,
53 #}
54 
55 # 启用或禁用下载器中间件
56 # See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
57 #DOWNLOADER_MIDDLEWARES = {
58 #    'MyFristScrapy.middlewares.MyfristscrapyDownloaderMiddleware': 543,
59 #}
60 
61 # 启用或禁用扩展
62 # See https://docs.scrapy.org/en/latest/topics/extensions.html
63 #EXTENSIONS = {
64 #    'scrapy.extensions.telnet.TelnetConsole': None,
65 #}
66 
67 # Configure item pipelines  配置项管道
68 # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
69 #ITEM_PIPELINES = {
70 #    'MyFristScrapy.pipelines.MyfristscrapyPipeline': 300,
71 #}
72 
73 # Enable and configure the AutoThrottle extension (disabled by default)
74 # 启用和配置自动油门扩展(默认情况下禁用)
75 # See https://docs.scrapy.org/en/latest/topics/autothrottle.html
76 #AUTOTHROTTLE_ENABLED = True
77 # The initial download delay    初始下载延迟
78 #AUTOTHROTTLE_START_DELAY = 5
79 # The maximum download delay to be set in case of high latencies
80 # 在高延迟情况下设置的最大下载延迟
81 #AUTOTHROTTLE_MAX_DELAY = 60
82 # The average number of requests Scrapy should be sending in parallel to
83 # each remote server
84 # 应该并行发送的平均请求数
85 # 每个远程服务器
86 #AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
87 # Enable showing throttling stats for every response received:
88 # 启用显示节流统计为每个收到的响应:
89 #AUTOTHROTTLE_DEBUG = False
90 
91 # Enable and configure HTTP caching (disabled by default)
92 # 启用和配置HTTP缓存(默认情况下禁用)
93 # See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
94 #HTTPCACHE_ENABLED = True
95 #HTTPCACHE_EXPIRATION_SECS = 0
96 #HTTPCACHE_DIR = 'httpcache'
97 #HTTPCACHE_IGNORE_HTTP_CODES = []
98 #HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
settings.py
  • middlewares.py中代码分析:自己定义中间件地方

引擎驱动过程

在 pycharm 中的 Terminal 中启动驱动 : scrape  crawl   budejie 
以下步骤完成后,准备工作就做完了。spider开启

 1   键入scrapy crawl xxx,驱动scrapy的引擎开始工作

 2   引擎开启,然后加载scrapy底层的依赖包与依赖程序(如:lxml、twisted等),加载完以后,引擎就可以正常工作

 3   引擎加载settings文件,从中读取settings中配置的组件信息,根据settings信息安排后面相关的工作

 4   引擎加载扩展文件,进行功能的扩展等

 5   加载当前开启的下载中间件

 6   加载当前开启的爬虫中间件

 7   加载管道组件

 8   前7步都是准备阶段,准工作完成以后,这里开始根据命令中指定的爬虫名字xxx创建一个爬虫对象

 9   引擎从爬虫对象的start_urls属性中提取出起始url,然后考察是否在allowed_domain中,如果在则将这个url放入到调度器的调度队列中,否则舍弃

10   调度器开始异步的对引擎放进来的url进行请求
    (【注意】请求的时候调度器每出队一个url就会开启一个异步的高效的下载器,
          下载器在下载的过程中会按照中间件的次序依次经过,
         最后将一层层中间件以后的请求发个服务器)

11   当下载器下载完成一个url数据以后会回调爬虫对象中的parse这个方法,
    并且将响应对象传递到response参数中(响应对象由下载器进入爬虫的过程会按照次序依次经过爬虫中间件)

12   爬虫对象接收到响应以后,解析并且把解析的数据返回(数据要可迭代)(如果在解析完一个数据以后还需要访问下一级页面,还需要在这里重新开启以下下载器)

13   如果管道开启,则每次迭代的数据会按照次序进入每一个管道,由管道进行后期的处理

14   所有的管道处理完成以后,爬虫就会被关闭掉,爬虫对象就会销毁,接着引擎就会关闭

Scrapy data flow(流程图)

      

Scrapy数据流是由执行的核心引擎(engine)控制,流程是这样的

  1、爬虫引擎ENGINE获得初始请求开始抓取。 

  2、爬虫引擎ENGINE开始请求调度程序SCHEDULER,并准备对下一次的请求进行抓取。 

  3、爬虫调度器返回下一个请求给爬虫引擎。

  4、引擎请求发送到下载器DOWNLOADER,通过下载中间件下载网络数据。

  5、一旦下载器完成页面下载,将下载结果返回给爬虫引擎ENGINE。

  6、爬虫引擎ENGINE将下载器DOWNLOADER的响应通过中间件MIDDLEWARES返回给爬虫SPIDERS进行处理。

  7、爬虫SPIDERS处理响应,并通过中间件MIDDLEWARES返回处理后的items,以及新的请求给引擎。

  8、引擎发送处理后的items到项目管道,然后把处理结果返回给调度器SCHEDULER,调度器计划处理下一个请求抓取。

  9、重复该过程(继续步骤1),直到爬取完所有的url请求。

各个组件介绍:

  • 爬虫引擎(ENGINE)  爬虫引擎负责控制各个组件之间的数据流,当某些操作触发事件后都是通过engine来处理。
  • 调度器(SCHEDULER)  调度接收来engine的请求并将请求放入队列中,并通过事件返回给engine。
  • 下载器(DOWNLOADER)  通过engine请求下载网络数据并将结果响应给engine。
  • Spider  Spider发出请求,并处理engine返回给它下载器响应数据,以items和规则内的数据请求(urls)返回给engine。
  • 管道项目(item pipeline)  负责处理engine返回spider解析后的数据,并且将数据持久化,例如将数据存入数据库或者文件。
  • 下载中间件  下载中间件是engine和下载器交互组件,以钩子(插件)的形式存在,可以代替接收请求、处理数据的下载以及将结果响应给engine。
  • spider中间件  spider中间件是engine和spider之间的交互组件,以钩子(插件)的形式存在,可以代替处理response以及返回给engine items及新的请求集。

 遗漏补充:

  scrapy中的request中的meta可以将变量传到response中使用[源码分析知]。 

  req.meta['post'] = post ---> post = response.meta['post']

  scrapy中的css解析是在源码中传变成xpath来进行解析的.

  scrapy默认采用深度优先搜索去爬去数据

  callback : 请求成功后 进行数据回调

  errorback:请求出错后,进行数据回调

  '//h3[contains(@class,"title")]/text()':h3属性中[contains]包含title字段


生如逆旅 一苇以航
原文地址:https://www.cnblogs.com/TMMM/p/10776296.html