zoukankan      html  css  js  c++  java
  • 爬虫入门三 scrapy


    title: 爬虫入门三 scrapy
    date: 2020-03-14 14:49:00
    categories: python
    tags: crawler

    scrapy框架入门

    1 scrapy简介

    爬虫框架是实现爬虫功能的一个软件结构和功能组件集合。
    官方网站:https://scrapy.org/
    Scrapy 0.24 文档: http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html

    Requests vs Scrapy
    相同点:两者都可以进行页面请求和爬取,Python爬虫的两个重要技术路线 两者可用性都好,文档丰富,入门简单 两者都没有处理js、提交表单、应对验证码等功能(可扩展)

    Requests
    页面级爬虫 功能库 并发性考虑不足,性能较差 重点在于页面下载 定制灵活 上手十分简单
    Scrapy
    网站级爬虫 框架 并发性好,性能较高 重点在于爬虫结构 一般定制灵活,深度定制困难 入门稍难

    2 scrapy 框架,数据流,数据类型

    2.1 scrapy框架(5+2)

    scrapy框架.PNG

    Spider
    (1) 解析Downloader返回的响应(Response) (2) 产生爬取项(scraped item) (3) 产生额外的爬取请求(Request)
    Engine
    (1)控制所有模块之间的数据流 (2)根据条件触发事件
    Downloader
    根据请求下载网页
    Scheduler
    对所有爬取请求进行调度管理
    Item Pipelines
    (1) 以流水线方式处理Spider产生的爬取项 (2) 由一组操作顺序组成,类似流水线 (3) 可能操作包括:清理、检验和查重爬取项中 的HTML数据、将数据存储到数据库
    Downloader Middleware
    目的:实施Engine、 Scheduler和Downloader    之间进行用户可配置的控制 功能:修改、丢弃、新增请求或响应
    Spider Middleware
    目的:对请求和爬取项的再处理 功能:修改、丢弃、新增请求或爬取项

    2.2 scrapy数据流

    scrapy数据流.PNG
    1.Engine从Spider处获得爬取请求(Request)
    2.Engine将爬取请求转发给Scheduler,用于调度
    3.Engine从Scheduler处获得下一个要爬取的请求
    4.Engine将爬取请求通过中间件发送给Downloader
    5.爬取网页后,Downloader形成响应(Response) 通过中间件发给Engine
    6.Engine将收到的响应通过中间件发送给Spider处理
    7.Spider处理响应后产生爬取项(scraped Item) 和新的爬取请求(Requests)给Engine
    8.Engine将爬取项发送给Item Pipeline(框架出口)
    9.Engine将爬取请求发送给Scheduler

    2.3 scrapy数据类型

    scrapy数据类型.PNG
    Request类
    Request对象表示一个HTTP请求,
    由Spider生成,由Downloader执行

    Response类
    Response对象表示一个HTTP响应,
    由Downloader生成,由Spider处理

    Item类
    Item对象表示一个从HTML页面中提取的信息内容
    由Spider生成,由Item Pipeline处理

    Item类似字典类型,可以按照字典类型操作
    scrapy数据类型2.PNG

    3 scrapy安装与使用

    3.1 scrapy安装

    3.1.1 anoconda安装

    conda install scrapy
    出现问题/慢,可以添加清华源

    3.1.2 pip安装 不推荐

    Python 3.5/3.6 下安装scrapy方法:
    (1)安装lxml: pip install lxml
    (2)下载对应版本的Twisted
     http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
    pip install D:Twisted-16.4.1-cp35-cp35m-win_amd64.whl
    (下载好的twisted模块的whl文件路径)
    (3)安装scrapy:pip install scrapy
    (4)安装关联模块pypiwin32:pip install pypiwin32

    3.2 scrapy常用链接

    scrapy常用命令.PNG

    3.3 示例

    3.3.1 创建项目

    命令行输入:
    scrapy startproject tutorial

    tutorial/
        scrapy.cfg
        tutorial/
            __init__.py
            items.py
            pipelines.py
            settings.py
            spiders/
                __init__.py
                ...
    
    scrapy.cfg: 项目的配置文件
    tutorial/: 该项目的python模块。之后您将在此加入代码
    
    tutorial/items.py: 项目中的item文件.
    tutorial/pipelines.py: 项目中的pipelines文件.
    tutorial/settings.py: 项目的设置文件.
    tutorial/spiders/: 放置spider代码的目录.
    

    3.3.2 定义item

    Item 是保存爬取到的数据的容器;其使用方法和python字典类似,并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。
    编辑 tutorial 目录中的 items.py 文件:

    import scrapy
    
    class DmozItem(scrapy.Item):
        title = scrapy.Field()
        link = scrapy.Field()
        desc = scrapy.Field() 
    

    Field 对象仅仅是内置的 dict 类的一个别名,并没有提供额外的方法或者属性。换句话说, Field 对象完完全全就是Python字典(dict)。被用来基于类属性(class attribute)的方法来支持 item声明语法 。

    3.2.3 编写spider

    Spider是用户编写用于从单个网站(或者一些网站)爬取数据的类。其包含了一个用于下载的初始URL,如何跟进网页中的链接以及如何分析页面中的内容, 提取生成 item 的方法。
    为了创建一个Spider,必须继承 scrapy.Spider 类, 且定义以下三个属性:

    name: 用于区别Spider。 该名字必须是唯一的,不可以为不同的Spider设定相同的名字。
    start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。
    parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。
    
    

    在项目中生成 spider 文件的两种方法:

    命令行输入 Scrapy genspider domain domain.com

    tutorial/spiders/目录下创建domain.py

    #爬取网页的内容
    # -*- coding: utf-8 -*-
    import scrapy
    
    class W3schoolSpider(scrapy.Spider):
        name = 'w3school'
        allowed_domains = ['w3school.com.cn']
        start_urls = ['http://www.w3school.com.cn/cssref/css_selectors.asp',
                      'http://www.w3school.com.cn/xpath/']
    
        def parse(self, response):
            filename = response.url.split("/")[-2]
            with open(filename, 'wb') as f:
                f.write(response.body)
            pass
    

    domin.PNG

    3.2.4 执行spider

    进入项目的根目录,执行下列命令启动spider:
    scrapy crawl w3school

    scrapyw3schoollog.PNG

    log包含定义在 start_urls 的初始URL,并且与spider中是一一对应的。在log中可以看到其没有指向其他页面( (referer:None) )。查看当前目录,两个包含url所对应的内容的文件被创建了: cssref, xpath, 正如我们的 parse 方法里做的一样。

    Scrapy为Spider的 start_urls 属性中的每个URL创建了 scrapy.Request 对象,并将 parse 方法作为回调函数(callback)赋值给了Request。Request对象经过调度,执行生成 scrapy.http.Response 对象并送回给spider parse() 方法。

    3.2.5 提取item Xpath

    Scrapy爬虫支持多种HTML信息提取方法:
    Beautiful Soup
    Lxml
    Re
    Xpath
    CSS

    3.2.6 Xpath selector

    XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
    常见的路径表达式如下:
    Xpathselector1.PNG

    xpathselector2.PNG

    谓语(Predicates)用来查找某个特定的节点或者包含某个指定的值的节点,嵌在方括号[]中。
    xpathselector3.PNG

    4 pycharm+anoconda+scrapy

    在anaconda按照scrapy,然后打开pycharm,添加anaconda到interpreter。

    然后在pycharm的命令行(下面的terminal)输入scrapy startproject xxx [mulu]

    然后file,open刚刚创建好的目录,就可以使用模板了
    pycharmscrapy.PNG

    5 建议

    第3部分的示例内容比较简略,比如说spider中就没有讲parse的定义参数是因为downloader返回了reponse对象。

    比如scrapy crwal w3school 中w3school是domin.py中的name。

    详细内容见 https://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html

    6 示例 豆瓣电影top250

    项目:scrapy startproject douban250

    6.1 item.py

    import scrapy
    
    class DoubanMovieItem(scrapy.Item):
        # 排名
        ranking = scrapy.Field()
        # 电影名称
        movie_name = scrapy.Field()
        # 评分
        score = scrapy.Field()
        # 评论人数
        score_num = scrapy.Field()
    
    

    6.2 DoubanMovieTop250.py (spider)

    from scrapy import Request
    from scrapy.spiders import Spider
    from douban250.items import DoubanMovieItem
    
    class DoubanMovieTop250Spider(Spider):
        name = 'douban_movie_top250'
        start_urls = ['https://movie.douban.com/top250']
    
        def parse(self, response):
            item = DoubanMovieItem()
            movies = response.xpath('//ol[@class="grid_view"]/li')
            for movie in movies:
                item['ranking'] = movie.xpath('.//div[@class="pic"]/em/text()').extract()[0]
                item['movie_name'] = movie.xpath('.//div[@class="hd"]/a/span[1]/text()').extract()[0]
                item['score'] = movie.xpath('.//div[@class="star"]/span[@class="rating_num"]/text()').extract()[0]
                item['score_num'] = movie.xpath('.//div[@class="star"]/span/text()').re(r'(d+)人评价')[0]
                yield item
    

    .xpath() 方法返回一个类 SelectorList 的实例, 它是一个新选择器的列表。
    .re() 方法用来通过正则表达式来提取数据,返回unicode字符串的列表。
    .extract() 方法串行化并将匹配到的节点返回一个unicode字符串列表。

    运行后报错403,豆瓣对爬虫有限制,需要修改访问的user-agent。
    将 start_urls = [‘https://movie.douban.com/top250’] 改为:

    class DoubanMovieTop250Spider(Spider):
        name = 'douban_movie_top250'
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
        }
    
        def start_requests(self):
            url = 'https://movie.douban.com/top250'
            yield Request(url, headers=self.headers)
    
    

    start_urls URL列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。因此,第一个被获取到的页面的URL将是该列表之一。 后续的URL将会从获取到的数据中提取。

    start_requests() 该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取的第一个Request。当spider启动爬取并且未指定URL时,该方法被调用。当指定了URL时,make_requests_from_url() 将被调用来创建Request对象。该方法仅仅会被Scrapy调用一次,默认实现是使用 start_urls 的url生成Request。

    parse(response) 当response没有指定回调函数时,该方法是Scrapy处理下载的response的默认方法。

    6.3 自动翻页 加到parse后

     next_url = response.xpath('//span[@class="next"]/a/@href').extract()
            if next_url:
                next_url = 'https://movie.douban.com/top250' + next_url[0]
                yield Request(next_url, headers=self.headers)
    

    两种方法:
    从当前页面中提取
    根据URL的变化规律构造所有页面地址(适用于页面的下一页地址为JS加载)

    6.4 运行

    运行爬虫程序
    scrapy crawl douban_movie_top250 -o douban.csv
    在项目所在目录下运行爬虫,并将结果输出到.csv文件。同样支持其他序列化格式:JSON、JSON lines、XML,和多种存储方式:本地文件系统路径,ftp,Amazon S3等

    报错

    KeyError: 'Spider not found: douban_movie_top250'
    

    原因是缩进问题。parse和start_requests都属于DoubanMovieTop250Spider类。

    然后是settings.py出错,改为

    BOT_NAME = 'douban250'
    
    SPIDER_MODULES = ['douban250.spiders']
    NEWSPIDER_MODULE = 'douban250.spiders'
    

    然后就可以运行

    6.5 输出的csv的编码问题

    但是打开csv文件
    douban乱码.PNG

    有很多问题。
    参考 https://blog.csdn.net/dayun555/article/details/79416447

    utf-8:全球通用编码
    ascii:能存储字母/数字/符号,美国专用
    gbk|gb2312|gb18030:能够存储汉字
    
    要生成经编码后的csv类型文件
    cmdline.execute(['scrapy', 'crawl', '爬虫文件名称', '-o', '文件名.csv', '-s', 'FEED_EXPORT_ENCODING="gb18030"'])
    例如:cmdline.execute(['scrapy', 'crawl', 'ivsky', '-o', 'img.csv', '-s', 'FEED_EXPORT_ENCODING="gb18030"'])
    
    要生成经编码后的json类型文件
    cmdline.execute(['scrapy', 'crawl', '爬虫文件名称', '-o', '文件名.json', '-s', 'FEED_EXPORT_ENCODING=utf-8'])
    
    例如:cmdline.execute(['scrapy', 'crawl', 'ivsky', '-o', 'img.json', '-s', 'FEED_EXPORT_ENCODING=utf-8'])
    

    修改settings,添加

    FEED_EXPORT_ENCODING = "gb18030"  # gbk不行
    

    然后再运行 scrapy crawl douban_movie_top250 -o douban.csv,内容就正常了

    douban250normal.PNG

    6.6 scrapy.cmdline.execute

    有这个模块可以不用手动输入。

    新建auto.py

    # -*- coding:utf-8 -*-
    from scrapy import cmdline
    
    # 方式一:注意execute的参数类型为一个列表
    cmdline.execute('scrapy crawl spidername'.split())
    
    # 方式二:注意execute的参数类型为一个列表
    cmdline.execute(['scrapy', 'crawl', 'spidername'])
    
    cmdline.execute(['scrapy', 'crawl', '爬虫文件名称', '-o', '文件名.json', '-s', 'FEED_EXPORT_ENCODING=utf-8'])
    

    然后运行该文件即可。

    这里

    from scrapy import cmdline
    
    cmdline.execute(['scrapy', 'crawl', 'douban_movie_top250', '-o', 'doubanauto.csv'])
    

    6.7 扩展。settings.py

    可以选择性的添加。

    ROBOTSTXT_OBEY = True		是否遵守robots.txt
    CONCURRENT_REQUESTS = 16	开启线程数量,默认16
    AUTOTHROTTLE_START_DELAY = 3	开始下载时限速并延迟时间
    AUTOTHROTTLE_MAX_DELAY = 60	高并发请求时最大延迟时间
    
    HTTPCACHE_ENABLED = True	
    HTTPCACHE_EXPIRATION_SECS = 0
    HTTPCACHE_DIR = ‘httpcache’
    HTTPCACHE_IGNORE_HTTP_CODES = []
    HTTPCACHE_STORAGE = ‘scrapy.extensions.httpcache.FilesystemCacheStorage’
    以上几个参数对本地缓存进行配置,如果开启本地缓存会优先读取本地缓存,从而加快爬取速度
    
    USER_AGENT = ‘projectname (+http://www.yourdomain.com)’
    对requests的请求头进行配置,比如可以修改为‘Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36’同样可以避免服务器返回403
    

    6.8 扩展。pipeline.py

    可以选择性的添加。

    当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。如果仅仅想要保存item,则不需要实现的pipeline。
    item pipeline的一些典型应用有:
    清理HTML数据
    验证爬取的数据(检查item包含某些字段)
    查重(并丢弃)
    将爬取结果保存到数据库中

    #去重过滤,丢弃那些已经被处理过的item。spider返回的多个item中包含有相同的id:
    from scrapy.exceptions import DropItem
    
    class DuplicatesPipeline(object):
    
        def __init__(self):
            self.ids_seen = set()
    
        def process_item(self, item, spider):
            if item['id'] in self.ids_seen:
                raise DropItem("Duplicate item found: %s" % item)
            else:
                self.ids_seen.add(item['id'])
                return item
    
    
  • 相关阅读:
    中间件
    Linux命令
    Ionic 2 Guide
    JSON WEB TOKENS
    用MSBuild和Jenkins搭建持续集成环境(2)
    用MSBuild和Jenkins搭建持续集成环境(1)
    全文检索和消息队列
    redis之如何配置jedisPool参数
    Redis Clients Handling
    redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
  • 原文地址:https://www.cnblogs.com/lqerio/p/13483672.html
Copyright © 2011-2022 走看看