这两天摸索了下scrapy,刚看文档的时候觉得有点生无可恋,scrapy框架个人还是觉得比较难懂的,需要学习的地方非常多,之前用beautifulsoup4爬过top250,比scrapy简单更容易理解!!
Scrapy简介
Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。 下面对每个组件都做了简单介绍,数据流如下所描述。
- Scrapy Engine
引擎负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。 详细内容查看下面的数据流(Data Flow)部分 - 调度器(Scheduler)
调度器从引擎接受request并将他们入队,以便之后引擎请求他们时提供给引擎 - 下载器(Downloader)
下载器负责获取页面数据并提供给引擎,而后提供给spider - Spiders
Spider是Scrapy用户编写用于分析response并提取item(即获取到的item)或额外跟进的URL的类。 每 个spider负责处理一个特定(或一些)网站 - Item Pipeline
Item Pipeline负责处理被spider提取出来的item。典型的处理有清理、 验证及持久化(例如存取到数 据库中) - 下载器中间件(Downloader middlewares)
下载器中间件是在引擎及下载器之间的特定钩子(specific hook),处理Downloader传递给引擎的 response。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能 - Spider中间件(Spider middlewares)
Spider中间件是在引擎及Spider之间的特定钩子(specific hook),处理spider的输入(response)和输出 (items及requests)。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能 - 数据流(Data flow)
Scrapy中的数据流由执行引擎控制,其过程如下:
引擎打开一个网站(open a domain),找到处理该网站的Spider并向该spider请求第一个要爬取的 URL(s)。
引擎从Spider中获取到第一个要爬取的URL并在调度器(Scheduler)以Request调度。
引擎向调度器请求下一个要爬取的URL。
调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求(request)方向)转发给下载 器(Downloader)。
一旦页面下载完毕,下载器生成一个该页面的Response,并将其通过下载中间件(返回(response)方 向)发送给引擎。
引擎从下载器中接收到Response并通过Spider中间件(输入方向)发送给Spider处理。
Spider处理Response并返回爬取到的Item及(跟进的)新的Request给引擎。
引擎将(Spider返回的)爬取到的Item给Item Pipeline,将(Spider返回的)Request给调度器。
(从第二步)重复直到调度器中没有更多地request,引擎关闭该网站
scrapy的流程如图,并且可归纳如下
- 首先下载器下载request回执的html等的response
- 然后下载器传给爬虫解析
- 接着爬虫解析后交给调度器过滤,查重等等
- 最后交给管道,进行爬取数据的处理
建议大家参考下中文版的Scrapy文档,看文档还是比较枯燥的,Scrapy又比较难懂(大神忽略),务必要有耐心!!!!!!
实战应用
首先下载Scrapy包
pip install scrapy
这样安装,windows平台应该是会报错的,我当时装Scrapy时废了很大劲才弄完。安装过程中Pycharm或者官网上找不到的模块可以上这个网址找Unofficial Windows Binaries for Python Extension Packages
Pywin32
接着,我们打开CMD,新建一个爬虫文件
scrapy startproject douban
C:\Users\ssaw\douban>tree /f
C:.
│ scrapy.cfg
│
└─douban
│ items.py
│ middlewares.py
│ pipelines.py
│ settings.py
│ init.py
│
└─spiders
init.py
简单介绍下这些文件
- scrapy.cfg: 项目的配置文件
- douban/: 该项目的python模块。之后您将在此加入代码
- douban/items.py: 项目中的item文件
- douban/pipelines.py: 项目中的pipelines文件
- douban/settings.py: 项目的设置文件
- douban/spiders/:放置spider代码的目录
编辑items.py文件
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class DoubanItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
movie_name = scrapy.Field()
movie_star = scrapy.Field()
movie_quote = scrapy.Field()
- 首先,引入Scrapy
- 接着,创建一个类,继承自scrapy.item,这个是用来储存要爬下来的数据的存放容器,类似orm的写法
- 我们要记录的是:电影的名字、电影的评分、电影的引述(quote)
现在,我们在spiders文件夹下创建douban_spider.py
在我们编写爬虫之前,先了解一下scrapy的爬取机制,scrapy提取数据有自己的一套机制。它们被称作选择器(seletors),因为他们通过特定的 XPath 或者 CSS 表达式来“选择” HTML文件中的某个部分。
之前我在博客上也总结过一篇使用Xpath模拟登陆GitHub有兴趣可以看一下
附上Xpath学习教程Xpath
获取网页数据
打开Chrome(F12),查找元素
豆瓣电影TOP250
红框圈出来的分别代表
movie_name = div[@class="hd"]/a/span/
movie_star = div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]
movie_quote = div[@class="bd"]/p[@class="quote"]/span[@class="inq"]
# _*_ coding=utf-8 _*_
from scrapy.spiders import Spider
from scrapy.selector import Selector
class DouBanSpider(Spider):
name = 'db'
start_urls = ['https://movie.douban.com/top250']
def parse(self, response):
# print(response.body)
selector = Selector(response)
# print(selector)
movies = selector.xpath('//div[@class="info"]')
for movie in movies:
movie_name = movie.xpath('div[@class="hd"]/a/span/text()').extract()
movie_star = movie.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract()
movie_quote = movie.xpath('div[@class="bd"]/p[@class="quote"]/span[@class="inq"]/text()').extract()
print(movie_name)
print(movie_star)
print(movie_quote)
我们打开setting.py,加上U-A
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
在CMD中输入scrapy crawl db,运行如下:
我们还可以在douban文件根目录创建一个main.py,这样就可以在Pycharm中运行了
from scrapy import cmdline
cmdline.execute("scrapy crawl db".split())
使用Item
Item对象是自定义的python字典。 您可以使用标准的字典语法来获取到其每个字段的值。(字段即是我们之前用Field赋值的属性),Spider将会将爬取到的数据以 Item 对象返回。
item = DoubanItem()
item['movie_name'] = movie_name
item['movie_star'] = movie_star
item['movie_quote'] = movie_quote
好了,现在我们先试着爬取单页面,查看下结果后,再去爬取多页面
from scrapy.spiders import Spider
from scrapy.selector import Selector
from douban.items import DoubanItem
class DouBanSpider(Spider):
name = 'db'
start_urls = ['https://movie.douban.com/top250']
def parse(self, response):
# print(response.body)
selector = Selector(response)
# print(selector)
movies = selector.xpath('//div[@class="info"]')
for movie in movies:
movie_name = movie.xpath('div[@class="hd"]/a/span/text()').extract()
movie_star = movie.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract()
movie_quote = movie.xpath('div[@class="bd"]/p[@class="quote"]/span[@class="inq"]/text()').extract()
#print(movie_name)
#print(movie_star)
#print(movie_quote)
item = DoubanItem()
item['movie_name'] = movie_name
item['movie_star'] = movie_star
item['movie_quote'] = movie_quote
yield item
print(movie_name)
print(movie_star)
print(movie_quote)
- 首先,我们先从scrapy中获得所需要的通用的 spider和 selector
- 接着,我们使用Item将爬取的数据返回
- 创建了一个DouBanSpider,继承了 scrapy.Spider 类, 且定义以下三个属性:
- name: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字
- start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一, 后续的URL则从初始的URL获取到的数据中提取。
- parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象
- seletor的方法返回后一定要用它的 extract()方法,来返回一个列表 ;extract()文档的定义:串行化并将匹配到的节点返回一个unicode字符串列表。 结尾是编码内容的百分比
- 接着,我们把得到的数据保存在Item中
- 最后,我们使用Feed exports来保存数据
- 这里使用了yield生成器函数,生成器函数和迭代器有密切关系,也并不是很容易理解,这一点需要多多学习
#看一个yield函数的示例
#函数在每次循环时都会产生一个值,之后将其返回给它的调用者
#函数不断的生成数字的平方
def gensquares(N):
for i in range(N):
yield i ** 2
for i in gensquares(5):
print(i, end=' ')
0 1 4 9 16
好了,spider暂时写完了,我们试着运行下
scrapy crawl db -o douban.json -t json
-o 后面是导出文件名,-t 后面是导出类型。
然后来看一下导出的结果,Pycharm打开json文件即可
打印出来的内容需要编码
我们换种方式,把文件格式保存为CSV,使用EXCEL打开
scrapy crawl db -o douban.csv -t csv
用excel打开后假如是一堆乱码,就使用记事本打开,把它“另存为”时,编码选择ANSI
好了,现在我们添加多页面链接,完整地把TOP250爬取下来
我们从Elements中找到翻页lianjie
next_page =response.selector.xpath('//span[@class="next"]/link/@href').extract()
if next_page:
next_page = next_page[0]
print(next_page)
yield Request(self.url + next_page, callback=self.parse)
CMD输入scrapy crawl db -o douban.csv -t csv ,开始运行
学习Scrapy需要反复查看文档、资料,这是个简单的学习总结,这两天准备再去学习MongoDB数据库,大家一起加油!!