zoukankan      html  css  js  c++  java
  • 使用 Scrapy 爬取去哪儿网景区信息

    Scrapy 是一个使用 Python 语言开发,为了爬取网站数据,提取结构性数据而编写的应用框架,它用途广泛,比如:数据挖掘、监测和自动化测试。安装使用终端命令 pip install Scrapy 即可。

    Scrapy 比较吸引人的地方是:我们可以根据需求对其进行修改,它提供了多种类型的爬虫基类,如:BaseSpider、sitemap 爬虫等,新版本提供了对 web2.0 爬虫的支持。

    1 Scrapy 介绍

    ![](https://img-blog.csdnimg.cn/20191019161603116.png#pic_center =560x420)

    1.1 组成

    • Scrapy Engine(引擎):负责 Spider、ItemPipeline、Downloader、Scheduler 中间的通讯,信号、数据传递等。

    • Scheduler(调度器):负责接受引擎发送过来的 Request 请求,并按照一定的方式进行整理排列、入队,当引擎需要时,交还给引擎。

    • Downloader(下载器):负责下载 Scrapy Engine(引擎) 发送的所有 Requests 请求,并将其获取到的 Responses 交还给 Scrapy Engine(引擎),由引擎交给 Spider 来处理。

    • Spider(爬虫):负责处理所有 Responses,从中解析提取数据,获取 Item 字段需要的数据,并将需要跟进的 URL 提交给引擎,再次进入 Scheduler(调度器)。

    • Item Pipeline(管道):负责处理 Spider 中获取到的 Item,并进行后期处理,如:详细解析、过滤、存储等。

    • Downloader Middlewares(下载中间件):一个可以自定义扩展下载功能的组件,如:设置代理、设置请求头等。

    • Spider Middlewares(Spider 中间件):一个可以自定扩展和操作引擎和 Spider 中间通信的功能组件,如:自定义 request 请求、过滤 response 等。

    总的来说就是:SpiderItem Pipeline 需要我们自己实现,Downloader MiddlewaresSpider Middlewares 我们可以根据需求自定义。

    1.2 流程梳理

    1)Spider 将需要发送请求的 URL 交给 Scrapy Engine 交给调度器;

    2)Scrapy Engine 将请求 URL 转给 Scheduler

    3)Scheduler 对请求进行排序整理等处理后返回给 Scrapy Engine

    4)Scrapy Engine 拿到请求后通过 Middlewares 发送给 Downloader

    5)Downloader 向互联网发送请求,在获取到响应后,又经过 Middlewares 发送给 Scrapy Engine

    6)Scrapy Engine 获取到响应后,返回给 SpiderSpider 处理响应,并从中解析提取数据;

    7)Spider 将解析的数据经 Scrapy Engine 交给 Item PipelineItem Pipeline 对数据进行后期处理;

    8)提取 URL 重新经 Scrapy Engine 交给 Scheduler 进行下一个循环,直到无 URL 请求结束。

    1.3 Scrapy 去重机制

    Scrapy 提供了对 request 的去重处理,去重类 RFPDupeFilterdupefilters.py 文件中,路径为:Python安装目录Libsite-packagesscrapy ,该类里面有个方法 request_seen 方法,源码如下:

    def request_seen(self, request):
        # 计算 request 的指纹
        fp = self.request_fingerprint(request)
        # 判断指纹是否已经存在
        if fp in self.fingerprints:
            # 存在
            return True
        # 不存在,加入到指纹集合中
        self.fingerprints.add(fp)
        if self.file:
            self.file.write(fp + os.linesep)
    

    它在 Scheduler 接受请求的时候被调用,进而调用 request_fingerprint 方法(为 request 生成一个指纹),源码如下:

    def request_fingerprint(request, include_headers=None):
        if include_headers:
            include_headers = tuple(to_bytes(h.lower())
                                     for h in sorted(include_headers))
        cache = _fingerprint_cache.setdefault(request, {})
        if include_headers not in cache:
            fp = hashlib.sha1()
            fp.update(to_bytes(request.method))
            fp.update(to_bytes(canonicalize_url(request.url)))
            fp.update(request.body or b'')
            if include_headers:
                for hdr in include_headers:
                    if hdr in request.headers:
                        fp.update(hdr)
                        for v in request.headers.getlist(hdr):
                            fp.update(v)
            cache[include_headers] = fp.hexdigest()
        return cache[include_headers]
    

    在上面代码中我们可以看到

    fp = hashlib.sha1()
    ...
    cache[include_headers] = fp.hexdigest()
    

    它为每一个传递过来的 URL 生成一个固定长度的唯一的哈希值。再看一下 __init__ 方法,源码如下:

    def __init__(self, path=None, debug=False):
    	self.file = None
    	self.fingerprints = set()
    	self.logdupes = True
    	self.debug = debug
    	self.logger = logging.getLogger(__name__)
    	if path:
    		self.file = open(os.path.join(path, 'requests.seen'), 'a+')
    		self.file.seek(0)
    		self.fingerprints.update(x.rstrip() for x in self.file)
    

    我们可以看到里面有 self.fingerprints = set() 这段代码,就是通过 set 集合的特点(set 不允许有重复值)进行去重。

    去重通过 dont_filter 参数设置,如图所示

    ![](https://img-blog.csdnimg.cn/20191019195952231.JPG#pic_center =600x120)

    dont_filterFalse 开启去重,为 True 不去重。

    2 实现过程

    制作 Scrapy 爬虫需如下四步:

    • 创建项目 :创建一个爬虫项目
    • 明确目标 :明确你想要抓取的目标(编写 items.py)
    • 制作爬虫 :制作爬虫开始爬取网页(编写 xxspider.py)
    • 存储内容 :设计管道存储爬取内容(编写pipelines.py)

    我们以爬取去哪儿网北京景区信息为例,如图所示:

    2.1 创建项目

    在我们需要新建项目的目录,使用终端命令 scrapy startproject 项目名 创建项目,我创建的目录结构如图所示:

    • spiders 存放爬虫的文件
    • items.py 定义数据类型
    • middleware.py 存放中间件
    • piplines.py 存放数据的有关操作
    • settings.py 配置文件
    • scrapy.cfg 总的控制文件

    2.2 定义 Item

    Item 是保存爬取数据的容器,使用的方法和字典差不多。我们计划提取的信息包括:area(区域)、sight(景点)、level(等级)、price(价格),在 items.py 定义信息,源码如下:

    import scrapy
    
    class TicketspiderItem(scrapy.Item):
        area = scrapy.Field()
        sight = scrapy.Field()
        level = scrapy.Field()
        price = scrapy.Field()
        pass
    

    2.3 爬虫实现

    在 spiders 目录下使用终端命令 scrapy genspider 文件名 要爬取的网址 创建爬虫文件,然后对其修改及编写爬取的具体实现,源码如下:

    import scrapy
    from ticketSpider.items import TicketspiderItem
    
    class QunarSpider(scrapy.Spider):
        name = 'qunar'
        allowed_domains = ['piao.qunar.com']
        start_urls = ['https://piao.qunar.com/ticket/list.htm?keyword=%E5%8C%97%E4%BA%AC&region=&from=mpl_search_suggest']
    
        def parse(self, response):
            sight_items = response.css('#search-list .sight_item')
            for sight_item in sight_items:
                item = TicketspiderItem()
                item['area'] = sight_item.css('::attr(data-districts)').extract_first()
                item['sight'] = sight_item.css('::attr(data-sight-name)').extract_first()
                item['level'] = sight_item.css('.level::text').extract_first()
                item['price'] = sight_item.css('.sight_item_price em::text').extract_first()
                yield item
            # 翻页
            next_url = response.css('.next::attr(href)').extract_first()
            if next_url:
                next_url = "https://piao.qunar.com" + next_url
                yield scrapy.Request(
                    next_url,
                    callback=self.parse
                )
    

    简单介绍一下:

    • name:爬虫名
    • allowed_domains:允许爬取的域名
    • atart_urls:爬取网站初始请求的 url(可定义多个)
    • parse 方法:解析网页的方法
    • response 参数:请求网页后返回的内容

    yield

    在上面的代码中我们看到有个 yield,简单说一下,yield 是一个关键字,作用和 return 差不多,差别在于 yield 返回的是一个生成器(在 Python 中,一边循环一边计算的机制,称为生成器),它的作用是:有利于减小服务器资源,在列表中所有数据存入内存,而生成器相当于一种方法而不是具体的信息,占用内存小。

    爬虫伪装

    通常需要对爬虫进行一些伪装,关于爬虫伪装可通过【Python 爬虫(一):爬虫伪装】做一下简单了解,这里我们使用一个最简单的方法处理一下。

    • 使用终端命令 pip install scrapy-fake-useragent 安装
    • 在 settings.py 文件中添加如下代码:
    DOWNLOADER_MIDDLEWARES = {
        # 关闭默认方法
        'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None, 
        # 开启
        'scrapy_fake_useragent.middleware.RandomUserAgentMiddleware': 400, 
    }
    

    2.4 保存数据

    我们将数据保存到本地的 csv 文件中,csv 具体操作可以参考:CSV 文件读写,下面看一下具体实现。

    首先,在 pipelines.py 中编写实现,源码如下:

    import csv
    
    class TicketspiderPipeline(object):
        def __init__(self):
            self.f = open('ticker.csv', 'w', encoding='utf-8', newline='')
            self.fieldnames = ['area', 'sight', 'level', 'price']
            self.writer = csv.DictWriter(self.f, fieldnames=self.fieldnames)
            self.writer.writeheader()
        def process_item(self, item, spider):
            self.writer.writerow(item)
            return item
    
        def close(self, spider):
            self.f.close()
    

    然后,将 settings.py 文件中如下代码:

    ITEM_PIPELINES = {
        'ticketSpider.pipelines.TicketspiderPipeline': 300,
    }
    

    放开即可。

    2.5 运行

    我们在 settings.py 的同级目录下创建运行文件,名字自定义,放入如下代码:

    from scrapy.cmdline import execute
    execute('scrapy crawl 爬虫名'.split())
    

    这个爬虫名就是我们之前在爬虫文件中的 name 属性值,最后在 Pycharm 运行该文件即可。

    参考:

    http://www.scrapyd.cn/doc/
    https://www.liaoxuefeng.com/wiki/897692888725344/923029685138624

    完整代码请关注文末公众号,后台回复 qs 获取。

  • 相关阅读:
    Tag文件使用
    微信开发 select选择框
    useGeneratedKeys的用法
    IBM MQ8.0常用操作
    C++对象在继承情况下的内存布局---多态实现的原理
    C++中的赋值操作符重载和拷贝构造函数
    C++中多态的概念和意义
    C 链表冒泡排序
    js 倒计时(可自定义时间)
    如何分析解决Android ANR
  • 原文地址:https://www.cnblogs.com/ityard/p/11875474.html
Copyright © 2011-2022 走看看