python scrapy学习笔记

发布时间:2019-09-19 08:00:29编辑:auto阅读(1538)

    scrapy是python最有名的爬虫框架之一,可以很方便的进行web抓取,并且提供了很强的定制型。


    一、安装scrapy

    # pip install scrapy


    二、基本使用

    1、初始化scrapy项目

    # scrapy startproject myscrapy


    初始化完成后的目录结构

    # tree
    .
    ├── myscrapy
    │   ├── __init__.py
    │   ├── items.py                      # 设置数据存储模板,用于结构化数据
    │   ├── middlewares.py                # 中间件,相当于钩子,对爬去前后做预处理
    │   ├── pipelines.py                  # 管道模块,处理spider模块分析好的数据,如保存入库等
    │   ├── settings.py                   # 配置文件,如并发数,是否开启缓存
    │   └── spiders
    │       ├── __init__.py
    │       └── myspider.py
    └── scrapy.cfg                         # 项目的配置文件


    一个例子爬取当当网的首页

    #!/usr/bin/python
    #coding:utf-8
    
    import scrapy
    
    class DangDang(scrapy.Spider):
        # 必须定义
        name = "dangdang"
        # 初始urls
        start_urls = [ 
            "http://www.dangdang.com"
        ]   
    
        # 默认response处理函数
        def parse(self, response):      # 抓取start_urls页面,自动执行parse回调函数
            current_url = response.url  # 当前请求的URL
            body = response.body        # 请求的内容
            print '请求的URL: {}\n请求的内容: {}'.format(current_url,body)


    运行

    # scrapy crawl dangdang                # 方式1
    # scrapy runspider dangdang.py         # 方式2


    爬虫开始爬取start_urls定义的url,并输出到文件中,最后输出爬去报告,会输出爬取得统计结果


    2、通过代码运行爬虫

    每次进入控制台运行爬虫还是比较麻烦的,而且不好调试,我们可以通过CrawlerProcess通过代码运行爬虫,新建一个模块run.py

    #!/usr/bin/python
    #coding:utf-8
    
    from scrapy.crawler import CrawlerProcess
    from scrapy.utils.project import get_project_settings
    from spiders.dangdang import DangDang
    
    # 获取setting.py模块的设置
    settings = get_project_settings()
    process = CrawlerProcess(settings=settings)
    
    # 添加spider,可以多个
    process.crawl(DangDang)                                                                                                                                       
    
    # 启动爬虫,阻塞知道爬取结束
    process.start()

    只需要执行python run.py就可以执行爬虫


    三、Scrapy类

    如上面的DangDang类,爬虫类继承自scrapy.Spider


    1、常用属性

    • name:爬虫的名字,必须唯一(如果在控制台使用的话,必须配置)

    • start_urls:爬虫初始爬取的链接列表

    • parse:response结果处理函数

    • custom_settings:自定义配置,覆盖settings.py中的默认配置


    2、常用方法

    • start_requests:启动爬虫的时候调用,默认是调用make_requests_from_url方法爬取start_urls的链接,可以在这个方法里面定制,如果重写了该方法,start_urls默认将不会被使用,可以在这个方法里面定制一些自定义的url,如登录,从数据库读取url等,本方法返回Request对象

    • make_requests_from_url:默认由start_requests调用,可以配置Request对象,返回Request对象

    • parse:response到达spider的时候默认调用,如果在Request对象配置了callback函数,则不会调用,parse方法可以迭代返回ItemRequest对象,如果返回Request对象,则会进行增量爬取


    3、Request与Response对象

      每个请求都是一个Request对象,Request对象定义了请求的相关信息(url, method, headers, body, cookie, priority)和回调的相关信息(meta, callback, dont_filter, errback),通常由spider迭代返回

      其中meta相当于附加变量,可以在请求完成后通过response.meta访问请求完成后,会通过Response对象发送给spider处理,常用属性有(url, status, headers, body, request, meta)



    四、选择器

    • 基本的选择器

    • 正则选择


    1、基本的选择器

    1. //                    ## 子孙

    2. /                     # 孩子

    3. //div[@class='info'][@id='1']  # 属性选择器

    4. //div/img/@src            # div下所有img的src值

    5. //div/a[1]               # div下第一个<a>

    6. //div/a[1]/text()          # div下第一个<a>的值


    例如

    wKioL1hiEMqhmYZ8AABFcjnhrYU527.jpg

    想要获取书名,可以写为: //ul[@class='list_aa listimg']/li//a/@title


    查找方式

    # 方法1,即将被废弃的
    from scrapy.selector import HtmlXPathSelector
    hxs = HtmlXPathSelector(response)
    items_HtmlXPathSelector = hxs.select('//ul[@class='list_aa listimg']/li//a/@title')
    print(len(items_HtmlXPathSelector))
    
    # 方法2
    from scrapy.selector import Selector
    items_Selector = Selector(response=response).xpath('//ul[@class='list_aa listimg']/li//a/@title')
    print(len(items_Selector))


    2、正则选择器

    <body>
        <li class="item-"><a href="link.html">first item</a></li>
        <li class="item-0"><a href="link1.html">first item</a></li>
        <li class="item-1"><a href="link2.html">second item</a></li>
    </body>


    书写方法://li[re:test(@class, "item-\d*")]//@href

    查找方式

    ret = Selector(response=response).xpath('//li[re:test(@class, "item-\d*")]//@href').extract()
    # re ---- 通过正则进行匹配
    # test -- 匹配


    五、使用scrapy爬取网站聊天记录和用户头像

    #!/usr/bin/python
    #coding:utf-8
    
    import scrapy
    from scrapy.selector import Selector
    import os
    import requests
    
    class NextSpider(scrapy.spiders.Spider):
        name = 'nextspider'
        start_urls = ["http://group.jobbole.com/27740/#comm-77724"]
    
        def parse(self,response):
            items_selector = Selector(response=response)
            items = items_selector.xpath('//ul[@class="cmnt-list"]/li')
    #       print items
            for i in range(len(items)):
                srcs = items_selector.xpath('//ul[@class="cmnt-list"]/li[%d]//div[@class="cmnt-header"]/a/img/@src'%i).extract()
                names = items_selector.xpath('//ul[@class="cmnt-list"]/li[%d]//div[@class="cmnt-header"]/div/span[1]/a/text()'%i).extract()
                msgs = items_selector.xpath('//ul[@class="cmnt-list"]/li[%d]//div[@class="cmnt-body"]/p/text()'%i).extract()                                      
                if srcs and names and msgs:
                    try:
                        img_url = srcs[0]
                        filename = names[0].encode('utf-8')
                        msg = ','.join([i.encode('utf-8') for i in msgs[1:]])
                        print '用户ID: {}\n发表信息: {}'.format(filename,msg)
                        img_dir = 'imgs'
                        path = os.path.join(os.getcwd(),img_dir,filename+'.png')
                        r = requests.get(img_url)
                        with open(path,'wb') as f:
                            for chunk in r.iter_content(chunk_size=1024):
                                if chunk:
                                    f.write(chunk)
                                    f.flush()
                            f.close()
                    except Exception,e:
                        print '错误: {}'.format(e)


    结果

    用户ID: 小编辑
    发表信息: 恭喜!,说说你是怎么追到的。然后再打广告 :)
    用户ID: 迷路的兔纸-->
    发表信息: 你这是赤果果的炫耀
    用户ID: sorry丶
    发表信息: 10月份去九寨沟,在青旅里面遇到我的那个她。
    ... ...


    图片

    # ls imgs/
    lishenluo.png  sorry丶.png  寻找隐世快乐.png  小编辑.png  忠文.png  熊绎.png  连时光都吐了.png  迷路的兔纸-->.png


    六、items.py中的Item类

    初始化后默认的Item类

    import scrapy
    
    class MyscrapyItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        pass


    scrapy.Item的用法与python中的字典用法基本一样,只是做了一些安全限制,属性定义使用Field,这里只是进行了声明,而不是真正的属性,使用的时候通过键值对操作,不支持属性访问


    七、Pipeline

    spider负责爬虫的配置,item负责声明结构化数据,而对于数据的处理,在scrapy中使用管道的方式进行处理,只要注册过的管道都可以处理item数据(处理,过滤,保存)


    示例:这里定义一个预处理管道PretreatmentPipeline.py,如果item的title为None,则设置为空字符串

    class PretreatmentPipeline(object):
        def process_item(self, item, spider):
            if item['msgs']:
                # 不让msgs为空
                item['msgs'] = ''
            return item


    八、setting.py文件

    setting.py文件中为我们提供了许多自带的功能,例如缓存、多线程等等,只需要修改配置即可

    1、缓存

    # 打开缓存
    HTTPCACHE_ENABLED = True
    
    # 设置缓存过期时间(单位:秒)
    #HTTPCACHE_EXPIRATION_SECS = 0
    
    # 缓存路径(默认为:.scrapy/httpcache)
    HTTPCACHE_DIR = 'httpcache'
    
    # 忽略的状态码
    HTTPCACHE_IGNORE_HTTP_CODES = []
    
    # 缓存模式(文件缓存)
    HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'


    2、多线程

    # 默认Request并发数:32
    CONCURRENT_REQUESTS = 32
    
    # 默认每个域名的并发数:16
    CONCURRENT_REQUESTS_PER_DOMAIN = 16
    
    # 每个IP的最大并发数:0表示忽略
    CONCURRENT_REQUESTS_PER_IP = 16


关键字