模块安装

Window : 推荐Anaconda

Ubuntu : 解决一些依赖

sudo apt-get install python-dev python-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev

模块简介

维基百科简介: Wikipedia

Scrapy(/ˈskreɪpi/ SKRAY-pee[2]是一个用Python编写的自由且开源的网络爬虫框架。它在设计上的初衷是用于爬取网络数据,但也可用作使用API来提取数据,或作为生成目的的网络爬虫[3]。该框架目前由网络抓取的开发与服务公司Scrapinghub公司维护。

Scrapy项目围绕“蜘蛛”(spiders)建构,蜘蛛是提供一套指令的自包含的爬网程序(crawlers)。遵循其他如Django框架的一次且仅一次精神[4],允许开发者重用代码将便于构建和拓展大型的爬网项目。Scrapy也提供一个爬网shell,开发者可用它测试对网站的效果。[5]

使用Scrapy的知名公司和产品有:Lyst[6][7]、Parse.ly[8]、Sayone Technologies[9]、Sciences Po Medialab[10]、Data.gov.uk的世界政府数据网站[11]等。

Scrapy诞生于网络聚合和电子商务公司Mydeco,它由Mydeco和Insophia公司的员工开发和维护。2008年8月首次以BSD许可证公开发布,2015年6月发布有里程碑意义的1.0版本[12]。2011年,Scrapinghub成为新的官方维护者[13][14]。

运行流程

  1. 首先从爬虫获取初始的请求
  2. 将请求放入调度模块,然后获取下一个需要爬取的请求
  3. 调度模块返回下一个需要爬取的请求给引擎
  4. 引擎将请求发送给下载器,依次穿过所有的下载中间件
  5. 一旦页面下载完成,下载器会返回一个响应包含了页面数据,然后再依次穿过所有的下载中间件。
  6. 引擎从下载器接收到响应,然后发送给爬虫进行解析,依次穿过所有的爬虫中间件
  7. 爬虫处理接收到的响应,然后解析出item和生成新的请求,并发送给引擎
  8. 引擎将已经处理好的item发送给管道组件,将生成好的新的请求发送给调度模块,并请求下一个请求
  9. 该过程重复,直到调度程序不再有请求为止。

简单使用

创建项目

  1. scrapy startproject dbtest dbtest2

dbtest2是子目录, dbtest是父目录
image.png
创建首个目录, 未指定父目录,则子父同名

  1. scrapy startproject db

image.png

命令说明

  1. scrapy <command> [options] [args]

Scrapy项目结构说明.png

创建爬虫文件

注意事项:为了目录结构清晰,需要切换到指定文件夹再开始创建,下面是一个错误演示

创建命令:
从模板中创建爬虫文件

  1. cd db
  2. scrapy genspider db250 https://movie.douban.com

image.png

正确示范

image.png
运行爬虫文件

  1. scrapy crawl db250

修改配置文件

修改robot.text设置,在项目的settings.py内,不遵循robot协议才能爬取数据

image.png

修改默认请求头,获取response响应数据

  1. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63"

image.png

查看日志文件,状态码200表示请求已成功,请求所希望的响应头或数据体将随此响应返回

image.png

开始测试网页

开启测试:

  1. scrapy shell https://movie.douban.com/top250

打印响应文件

  1. response.text

解析指定源码块

  1. response.xpath('//div[@class = "info"]')

检查长度

  1. len(response.xpath('//div[@class = "info"]'))

解析电影名称

  1. node_list = response.xpath('//div[@class="info"]')
  2. for node in node_list:
  3. film_name = node.xpath("./div/a/span/text()").extract()[0]
  4. print(film_name)

注意:为了抓取纯文字,需要在解析代码后面添加一个extract()方法

image.png

细节处理
json编码处理 不适用ASCⅡ
image.png

新建终端调试爬虫文件

image.png

GBK编码报错

image.png

解决方案

image.png

解决输出文档不换行的问题

image.png

image.png

管道存储数据

修改items.py
注意:管道结构和文本元素个数完全一致
image.png

在爬虫文件(db250)中创建管道

注意:需要从items.py中导出DbItem

image.png

在爬虫文件中生成对应管道

image.png

关于数据对应的问题

db250中的item_pipe, item必须和items.py中的item一一对应,尤其是键值对

代码:

  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. '''
  7. 定义字段名称,获取到的数据与管道的结构对应,才能一一存储
  8. '''
  9. class DbItem(scrapy.Item):
  10. # define the fields for your item here like:
  11. # name = scrapy.Field()
  12. film_name = scrapy.Field()
  13. director_name = scrapy.Field()
  14. score = scrapy.Field()
  15. pass

image.png

  1. import json
  2. import scrapy
  3. from ..items import DbItem # 是一个安全的字典
  4. class Db250Spider(scrapy.Spider): # 继承基础类
  5. name = 'db250' # 爬虫文件名字,必须存在且唯一
  6. # allowed_domains = ['https://moive.douban.com'] # 允许的域名 相当于防火墙, 可以不存在,可以访问任何网站
  7. start_urls = ['https://movie.douban.com/top250'] # 初始URL, 必须存在
  8. def parse(self, response): # 解析函数,处理响应数据
  9. print('***' * 30)
  10. print('***' * 30)
  11. print('***' * 30)
  12. print(response)
  13. node_list = response.xpath('//div[@class="info"]')
  14. with open("film.txt", "w", encoding="utf-8") as f:
  15. for node in node_list:
  16. # 电影名字
  17. film_name = node.xpath('//div/a/span/text()').extract()[0]
  18. # 导演信息
  19. director_name = node.xpath("./div/p/text()").extract()[0].strip()
  20. # 评分信息
  21. score = node.xpath('./div/div/span[@property="v:average"]/text()').extract()[0]
  22. # 非管道存储
  23. item = {}
  24. item['film_name'] = film_name
  25. item['director_name'] = director_name
  26. item['score'] = score
  27. content = json.dumps(item, ensure_ascii=False)
  28. f.write(content + "\n")
  29. # 使用管道存储
  30. item_pipe = DbItem() # 创建DbItem对象,当作字典来使用
  31. item_pipe['film_name'] = film_name
  32. item_pipe['director_name'] = director_name
  33. item_pipe['score'] = score
  34. yield item_pipe # 不能使用return , 不影响代码的执行

image.png

在settings.py中开启管道

image.png

发起多个页面的请求

避免被封IP地址,先获取两页

最后一个语句生成网页访问,提交网页给引擎,引擎拿到网页将做出访问,将响应数据传递给parse解析
image.png

主文件代码(db250)

  1. import json
  2. import scrapy
  3. from ..items import DbItem # 是一个安全的字典
  4. class Db250Spider(scrapy.Spider): # 继承基础类
  5. name = 'db250' # 爬虫文件名字,必须存在且唯一
  6. # allowed_domains = ['https://moive.douban.com'] # 允许的域名 相当于防火墙, 可以不存在,可以访问任何网站
  7. start_urls = ['https://movie.douban.com/top250'] # 初始URL, 必须存在
  8. page_num = 0
  9. def parse(self, response): # 解析函数,处理响应数据
  10. print('***' * 30)
  11. print('***' * 30)
  12. print('***' * 30)
  13. print(response)
  14. node_list = response.xpath('//div[@class="info"]')
  15. with open("film.txt", "w", encoding="utf-8") as f:
  16. for node in node_list:
  17. # 电影名字
  18. film_name = node.xpath('./div/a/span/text()').extract()[0]
  19. # 导演信息
  20. director_name = node.xpath("./div/p/text()").extract()[0].strip()
  21. # 评分信息
  22. score = node.xpath('./div/div/span[@property="v:average"]/text()').extract()[0]
  23. # 非管道存储
  24. item = {}
  25. item['film_name'] = film_name
  26. item['director_name'] = director_name
  27. item['score'] = score
  28. content = json.dumps(item, ensure_ascii=False)
  29. f.write(content + "\n")
  30. # 使用管道存储
  31. item_pipe = DbItem() # 创建DbItem对象,当作字典来使用
  32. item_pipe['film_name'] = film_name
  33. item_pipe['director_name'] = director_name
  34. item_pipe['score'] = score
  35. yield item_pipe # 不能使用return , 不影响代码的执行
  36. # 发起新一页的请求
  37. # 构造URL
  38. self.page_num += 1
  39. if self.page_num == 3:
  40. return
  41. page_url = "https://movie.douban.com/top250?start={}&filter=".format(self.page_num*25)
  42. print(page_url)
  43. yield scrapy.Request(page_url)