• 一份详实的 Scrapy 爬虫教程,从原理到实战


    一、Scrapy框架简介

    Scrapy是:由Python语言开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据,只需要实现少量的代码,就能够快速的抓取。

    二、运行原理

    Scrapy框架的运行原理看下面一张图就够了(事实上原理是比较复杂的,也不是三言两语能够说清楚的,因此感兴趣的读者可以进一步阅读更多的相关文章来了解,本文不做过多讲解

    Scrapy主要包括了以下组件:

    • 引擎(Scrapy Engine)

    • Item 项目

    • 调度器(Scheduler)

    • 下载器(Downloader)

    • 爬虫(Spiders)

    • 项目管道(Pipeline)

    • 下载器中间件(Downloader Middlewares)

    • 爬虫中间件(Spider Middlewares)

    • 调度中间件(Scheduler Middewares)

    三. 入门

    3.1安装

    第一种:在命令行模式下使用pip命令即可安装:

    $ pip install scrapy
    

    第二种:首先下载,然后再安装:

    1. $ pip download scrapy -d ./
    2. # 通过指定国内镜像源下载 
    3. $pip download  -i https://pypi.tuna.tsinghua.edu.cn/simple scrapy -d ./

    进入下载目录后执行下面命令安装:

    $ pip install Scrapy-1.5.0-py2.py3-none-any.whl
    

    3.2使用

    使用大概分为下面四步 1 创建一个scrapy项目

    scrapy startproject mySpider
    

    2 生成一个爬虫

    scrapy genspider demo "demo.cn"
    

    3 提取数据

    完善spider 使用xpath等
    

    4 保存数据

    pipeline中保存数据
    

    3.3 程序运行

    在命令中运行爬虫

    scrapy crawl qb     # qb爬虫的名字
    

    在pycharm中运行爬虫

    1. from scrapy import cmdline
    2. cmdline.execute("scrapy crawl qb".split())

    四、基本步骤

    Scrapy 爬虫框架的具体使用步骤如下:

    1. 选择目标网站

    2. 定义要抓取的数据(通过Scrapy Items来完成的)

    3. 编写提取数据的spider

    4. 执行spider,获取数据

    5. 数据存储

    五. 目录文件说明

    当我们创建了一个scrapy项目后,继续创建了一个spider,目录结构是这样的:

    下面来简单介绍一下各个主要文件的作用:

    scrapy.cfg :项目的配置文件

    mySpider/ :项目的Python模块,将会从这里引用代码

    mySpider/items.py :项目的目标文件

    mySpider/pipelines.py :项目的管道文件

    mySpider/settings.py :项目的设置文件

    mySpider/spiders/ :存储爬虫代码目录

    5.1 scrapy.cfg文件

    项目配置文件。这个是文件的内容:

    1. # Automatically created by: scrapy startproject
    2. #
    3. For more information about the [deploy] section see:
    4. # https://scrapyd.readthedocs.io/en/latest/deploy.html
    5. [settings]
    6. default = mySpider.settings
    7. [deploy]
    8. #url = http://localhost:6800/
    9. project = mySpider

    5.2 mySpider**/**

    项目的Python模块,将会从这里引用代码

    5.3 mySpider/items.py

    项目的目标文件

    1. # Define here the models for your scraped items
    2. #
    3. # See documentation in:
    4. # https://docs.scrapy.org/en/latest/topics/items.html
    5. import scrapy
    6. class MyspiderItem(scrapy.Item):
    7.     # define the fields for your item here like:
    8.     # name = scrapy.Field()
    9.     pass

    定义scrapy items的模块,示例: name = scrapy.Field()

    5.4 mySpider/pipelines.py

    项目的管道文件

    1. # Define your item pipelines here
    2. #
    3. # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    4. # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
    5. # useful for handling different item types with a single interface
    6. from itemadapter import ItemAdapter
    7. class MyspiderPipeline:
    8.     def process_item(self, item, spider):
    9.         return item

    这个文件也就是我们说的管道,当Item在Spider中被收集之后,它将会被传递到Item Pipeline(管道),这些Item Pipeline组件按定义的顺序处理Item。每个Item Pipeline都是实现了简单方法的Python类,比如决定此Item是丢弃而存储。以下是item pipeline的一些典型应用:

    • 验证爬取的数据(检查item包含某些字段,比如说name字段)

    • 查重(并丢弃)

    • 将爬取结果保存到文件或者数据库中

    5.5 mySpider/settings.py

    项目的设置文件

    1. # Scrapy settings for mySpider project
    2. ...
    3. BOT_NAME = 'mySpider' # scrapy项目名
    4. SPIDER_MODULES = ['mySpider.spiders']
    5. NEWSPIDER_MODULE = 'mySpider.spiders'
    6. .......
    7. # Obey robots.txt rules
    8. ROBOTSTXT_OBEY = False # 是否遵守协议,一般给位false,但是创建完项目是是True,我们把它改为False
    9. # Configure maximum concurrent requests performed by Scrapy (default16)
    10. #CONCURRENT_REQUESTS = 32 # 最大并发量 默认16
    11. ......
    12. #DOWNLOAD_DELAY = 3 # 下载延迟 3
    13. Override the default request headers: # 请求报头,我们打开
    14. DEFAULT_REQUEST_HEADERS = {
    15.   'Accept''text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    16.   'Accept-Language''en',
    17. }
    18. # 爬虫中间件
    19. #SPIDER_MIDDLEWARES = {
    20. #    'mySpider.middlewares.MyspiderSpiderMiddleware'543,
    21. #}
    22. # 下载中间件
    23. #DOWNLOADER_MIDDLEWARES = {
    24. #    'mySpider.middlewares.MyspiderDownloaderMiddleware'543,
    25. #}
    26. ......
    27. # Configure item pipelines
    28. # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
    29. #ITEM_PIPELINES = {
    30. #    'mySpider.pipelines.MyspiderPipeline'300, # 管道
    31. #}
    32. .......

    省略号省略代码,一般重要点,给了注释

    6.mySpider/spiders/ :存储爬虫代码目录

    1. import scrapy
    2. class DbSpider(scrapy.Spider):
    3.     name = 'db'
    4.     allowed_domains = ['douban.com'# 可以修改
    5.     start_urls = ['http://douban.com/'# 开始的url也可以修改
    6.     def parse(self, response):
    7.         # pass

    六. Scrapy shell

    Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据,但是一般使用的不多。感兴趣的查看官方文档:

    官方文档

    http://scrapy-chs.readthedocs.io/zh_CN/latest/topics/shell.html
    

    Scrapy Shell根据下载的页面会自动创建一些方便使用的对象,例如 Response 对象,以及 Selector 对象 (对HTML及XML内容)

    • 当shell载入后,将得到一个包含response数据的本地 response 变量,输入 response.body将输出response的包体,输出 response.headers 可以看到response的包头。

    • 输入 response.selector 时, 将获取到一个response 初始化的类 Selector 的对象,此时可以通过使用 response.selector.xpath()response.selector.css() 来对 response 进行查询。

    • Scrapy也提供了一些快捷方式, 例如 response.xpath()response.css()同样可以生效(如之前的案例)。

    Selectors选择器

    Scrapy Selectors 内置 XPath 和 CSS Selector 表达式机制

    Selector有四个基本的方法,最常用的还是xpath:

    • xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表

    • extract(): 序列化该节点为字符串并返回list

    • css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表,语法同 BeautifulSoup4

    • re(): 根据传入的正则表达式对数据进行提取,返回字符串list列表

    七、案例实战

    本节,我将使用Scrapy爬取站酷数据作为示例

    7.1 案例说明

    既然已经初步了解了scrapy的工作流程以及原理,我们来做一个入门的小案例,爬取站酷首页推荐的item信息。如下图所示,一个小方框就是一个item信息。我们要提取每一个item的六个组成部分:

    1. imgLink(封面图片链接);

    2. title(标题);

    3. types(类型);

    4. vistor(人气);

    5. comment(评论数);

    6. likes(推荐人数)

    然后只是一个页面的item,我们还要通过翻页实现批量数据采集。

    7.2 文件配置

    目录结构

    在上一篇中我们说明了新建scrapy项目(zcool)spider项目(zc),这里不再赘述,然后得到我们的目录结构如下图所示:

    start.py文件

    然后为了方便运行,在zcool目录下新建start文件。并进行初始化设置。

    1. from scrapy import cmdline
    2. cmdline.execute('scrapy crawl zc'.split())

    settings.py文件

    在这个文件里我们需要做几样设置👇

    避免在程序运行的时候打印log日志信息

      LOG_LEVEL = 'WARNING' 
    
     ROBOTSTXT_OBEY = False 
    

    添加请求头:

    打开管道:

    item.py文件

    1. import scrapy
    2. class ZcoolItem(scrapy.Item):
    3.     # define the fields for your item here like:
    4.     imgLink = scrapy.Field() # 封面图片链接
    5.     title = scrapy.Field() # 标题
    6.     types = scrapy.Field() # 类型
    7.     vistor = scrapy.Field() # 人气
    8.     comment = scrapy.Field() # 评论数
    9.     likes = scrapy.Field() # 推荐人数

    7.3 页面数据提取

    首先我们在站酷页面使用xpath-helper测试一下:

    然后zc.py文件里面初步测试一下:

    1. def parse(self, response):
    2.     divList = response.xpath('//div[@class="work-list-box"]/div')
    3.     print(len(divList))

    运行结果如下图所示:

    没有问题,然后我们对各种信息分别解析提取,

    1. def parse(self, response):
    2.     divList = response.xpath('//div[@class="work-list-box"]/div')
    3.     for div in divList:
    4.         imgLink = div.xpath("./div[1]/a/img/@src").extract()[0] # 1.封面图片链接
    5.   ...  2.title(标题);3 types(类型);4vistor(人气);5comment(评论数)  ....
    6.         likes = div.xpath("./div[2]/p[3]/span[3]/@title").extract_first() # 6likes(推荐人数)
    7.         item = ZcoolItem(imgLink=imgLink,title=title,types=types,vistor=vistor,comment=comment,likes=likes)
    8.         yield item

    解释: xpath提取数据方法:

    S.N.方法 & 描述
    extract()返回的是符合要求的所有的数据,存在一个列表里。
    extract_first()返回的hrefs 列表里的第一个数据。
    get()和extract_first()方法返回的是一样的,都是列表里的第一个数据。
    getall()和extract()方法一样,返回的都是符合要求的所有的数据,存在一个列表里。

    注意:

    get() 、getall() 方法是新的方法,extract() 、extract_first()方法是旧的方法。extract() 、extract_first()方法取不到就返回None。get() 、getall() 方法取不到就raise一个错误。

    item实例创建(yield上面一行代码)

    这里我们之前在目录文件配置的item文件中已经进行了设置,对于数据存储,我们在爬虫文件中开头要导入这个类:

    from zcool.items import ZcoolItem
    

    然后使用yield返回数据。

    为什么使用yield而不是return

    不能使用return这个无容置疑,因为要翻页,使用return直接退出函数;而对于yield:在调用for的时候,函数内部不会立即执行,只是返回了一个生成器对象。在迭代的时候函数会开始执行,当在yield的时候,会返回当前值(i)。之后的这个函数会在循环中进行,直到没有下一个值。

    7.4 翻页实现批量数据采集

    通过上面的代码已经可以初步实现数据采集,只不过只有第一页的,如下图所示:

    但是我们的目标是100个页面的批量数据采集,所以代码还需要修改。针对翻页这里介绍两种方式:

    方式一:我们首先在页面中定位到下一页的按钮,如下图所示:

    然后编写如下代码,在for循环完毕后。

    1. next_href = response.xpath("//a[@class='laypage_next']/@href").extract_first()
    2. if next_href:
    3.     next_url = response.urljoin(next_href)
    4.     print('*' * 60)
    5.     print(next_url)
    6.     print('*' * 60)
    7.     request = scrapy.Request(next_url)
    8.     yield request

    scrapy.Request(): 把下一页的url传递给Request函数,进行翻页循环数据采集。

    https://www.cnblogs.com/heymonkey/p/11818495.html # scrapy.Request()参考链接
    

    注意方式一只有下一页按钮它的href对应属性值和下一页的url一致才行。

    方式二:定义一个全局变量count = 0,每爬取一页数据,令其加一,构建新的url,再使用scrapy.Request() 发起请求。

    如下图所示:

    1. count = 1
    2. class ZcSpider(scrapy.Spider):
    3.     name = 'zc'
    4.     allowed_domains = ['zcool.com.cn']
    5.     start_urls = ['https://www.zcool.com.cn/home?p=1#tab_anchor'] # 第一页的url
    6.     def parse(self, response):
    7.         global count
    8.         count += 1
    9.         
    10.         for div in divList:
    11.     # ...xxx...
    12.             yield item
    13.         next_url = 'https://www.kuaikanmanhua.com/tag/0?state=1&sort=1&page={}'.format(count)
    14.         yield scrapy.Request(next_url)

    这两种方式在实际案例中择机采用。

    7.5 数据存储

    数据存储是在pipline.py中进行的,代码如下:

    1. from itemadapter import ItemAdapter
    2. import csv
    3. class ZcoolPipeline:
    4.     def __init__(self): 
    5.         self.f = open('Zcool.csv','w',encoding='utf-8',newline='')       # line1
    6.         self.file_name = ['imgLink''title','types','vistor','comment','likes']  # line2
    7.         self.writer = csv.DictWriter(self.f, fieldnames=self.file_name)     # line3
    8.         self.writer.writeheader()              # line4
    9.     def process_item(self, item, spider):
    10.         self.writer.writerow(dict(item))              # line5
    11.         print(item)
    12.         return item                  # line6 
    13.     def close_spider(self,spider):
    14.         self.f.close()

    解释:

    • line1: 打开文件,指定方式为写,利用第3个参数把csv写数据时产生的空行消除

    • line2: 设置文件第一行的字段名,注意要跟spider传过来的字典key名称相同

    • line3: 指定文件的写入方式为csv字典写入,参数1为指定具体文件,参数2为指定字段名

    • line4: 写入第一行字段名,因为只要写入一次,所以文件放在__init__里面

    • line5: 写入spider传过来的具体数值,注意在spider文件中yield的item,是一个由类创建的实例对象,我们写入数据时,写入的是 字典,所以这里还要转化一下。

    • line6: 写入完返回

    7.6 程序运行

    因为之前创建了start.py文件,并且对它就行了初始化设置,现在运行爬虫程序不需要在控制台中输入命令:

    scrapy crawl zc(爬虫项目名)
    

    直运行start.py文件:得到如下结果:

    对应于页面:

    打开csv文件如下图所示:(由于csv文件在word中乱码了,此处我是用Notepad++打开)

    没有问题,数据采集完毕。

    7.7. 总结

    入门案例,需要细心,主要是基础知识的巩固,以便于为进阶学习做好准备。

  • 相关阅读:
    排序:堆排序算法分析以及插入删除操作
    Pandas数据类型转换
    基于单片机仓库温湿度监测报警系统仿真设计
    Android 实现 Alexa App-to-App Account Linking
    【北亚数据恢复】如何保证LINUX执行FSCK后的数据不出问题?
    Nacos部署及使用
    MyBatis(二)
    使用python生成文字图片,画圆圈 ,生成圆形图片
    一文搞懂cookie与session
    [Linux] 如何在 Linux 电脑上制作专业的视频教程
  • 原文地址:https://blog.csdn.net/npm_run_dev__/article/details/126917864