Scrapy简介
Scrapy是一个用Python语言(基于Twisted框架)编写的开源网络爬虫框架.
Scrapy安装
linux:
conda install scrapy
win:略
Mac:没钱用
测试
import scarpy
print(scrapy.version_info)
(1, 5, 0)
编写第一个Scrapy
创建项目的命令:
结构目录:
练习网站
http://books.toscrape.com/
分析网站
右键检查元素
next的url:
<li class="next"><a href="page-3.html">next</a></li>
是一个相对地址
实现spider
- name属性
一个项目中可能有多个爬虫,每个爬虫的name属性是自身的唯一标示,
name不能重复 例子中name=‘books’
- start_urls属性
一个爬虫开始的页面(可以为多个),起始爬取点'http://books.topcrape.com'
- parse方法
页面下载完成后 Scrapy会回调一个页面解析函数(默认parse方法),完成
1.提取页面中的数据(XPath或css选择器)
2.提取页面中的链接,并产生对链接页面的下载请求
# -*- coding: utf-8 -*-
import scrapy
class BooksSpider(scrapy.Spider):
name = 'books'
# 定义爬虫起点
start_urls = ['http://books.toscrape.com/']
# def start_requests(self):
# yield scrapy.Request('http://books.toscrape.com/',
# callback=self.parse_book,
# headers={'User-Agent': 'Mozilla/5.0'},
# dont_filter=True)
# # 改用parse_book作为回调函数
# def parse_book(response):
#
# pass
# def parse(self, response):
# # 提取数据
# # <article class="product_pod">
# # 每一本书的信息在<article class="product_pod"中>
# # 用css()方法找到所有这样的article元素,并依次迭代
# for book in response.css('article.product_pod'):
# # 书名信息在aritcle>h3>a元素的title属性里
# # <a href="how-music-works_979/index.html" title="How Music Works">How Music Works</a>
# name = book.xpath('./h3/a/@title').extract_first()
#
# # 书价在<p class="price_color">£37.32</p>的text中
# price = book.css('p.price_color::text').extract_first()
# yield {
# 'name': name,
# 'price': price,
# }
#
# # 提取链接
# # 下一页的url在<li class="next"><a href="page-3.html">next</a></li>
# next_url = response.css('ul.pager li.next a::attr(href)').extract_first()
# if next_url:
# # 若找不到下一页,得到绝对路径,构造新的requset对象
# next_url = response.urljoin(next_url)
# # yield scrapy.Request(next_url, callback=self.parse)
def parse(self, response):
for book_url in response.css("article.product_pod > h3 > a ::attr(href)").extract():
yield scrapy.Request(response.urljoin(book_url), callback=self.parse_book_page)
# 然后是获取相应内容,并创建解析函数
next_page = response.css("li.next > a ::attr(href)").extract_first()
if next_page:
yield scrapy.Request(response.urljoin(next_page), callback=self.parse)
# 关键之处之一,找到下一个链接
def parse_book_page(self, response):
# 解析函数,我们在Scrapy中使用,Selector与xpath选择器,css选择器与一些其他Python代码实现该功能
item = {}
product = response.css("div.product_main")
item["title"] = product.css("h1 ::text").extract_first()
item['category'] = response.xpath(
"//ul[@class='breadcrumb']/li[@class='active']/preceding-sibling::li[1]/a/text()"
).extract_first()
item['description'] = response.xpath(
"//div[@id='product_description']/following-sibling::p/text()"
).extract_first()
item['price'] = response.css('p.price_color ::text').extract_first()
yield item
Scrapy框架结构工作原理
- ENGING 引擎,框架的核心,其他组件在其控制下工作 内部组件
- SCHENDULER 调度器,负责对spider提交的下载请求进行调度 内部组件
- DOWNLOAD 下载器 ,下载页面(request response) 内部组价
- spider 提取页面中的数据 产生对新页面的下载请求 用户实现
- MIDDLEWARE 中间件,负责对request response对象进行处理 可选组价
- ITEM PIPELINE 数据管道 对爬去的数据进行处理
spider
- request :Scrapy中http请求对象
- response:Scrapy中响应
item:从页面中爬去一项数据
request 和response好比血液 item好比代谢产物
request response
Request(url,[,callback,method='GET',headers,body,cookies,meta,encoding='utf-8',priority=0,priority = 0,dont_filter=False,errback])
- url地址
- callback 页面解析函数callback类型,request对象请求的页面下载完成后,该参数指定的页面解析函数被调用。默认Spider的parse方法
- method Http请求方法,默认‘GET’
- headers Http请求的头部字典,dict类型。若其中某些值为NONE,不发送该http头部{‘Cookie’:None}:禁止发送cookie
- body Http请求的正文,bytes或str
- cookie dict类型
- meta request的元数据字典,dict类型,用于给框架中的其他组件传递信息。其他组件也可以用request对象的meta属性访问该元数据字典(request.meta),也用给相应处理函数传递信息
- ecoding utf-8
- priority 请求的优先级默认值为0 优先级高的先下载
- dont_filter 默认dont_filter=false 避免重复下载一个url 。=true时,强制下载一个url
- errback 请求异常或者404时的回调函数
response用来描述一个http响应,response是一个基类,如下子类
- TextResponse
- HtmlResponse
- XmlResponse
三者只有细微的差异,以HtmlResponse讲解 - url str
- status 相应状态码 200 404
- header 头部 字典类型
response.header.get('Content-Type')
response.headers.getlist('Set-cookie')
- body 正文文本 bytes
- text str 由response.body使用response.ecoding解码得到
response.text = response.decode(response.encoding)
- encoding
- requset
- meat 将要传递给响应处理函数的信息通过meta参数传递;再有response.meta取出
- selector 在response中提取数据
- xpath(query) 使用xpath在response中提取数据,实际是response.selector.xpath方法的快捷方式
- css(query)使用css在response中提取数据, 是response.selector.css的快捷
- urljoin(url) 构造绝对的url 例如response.url为http://www.example.com/a url为b/index.html调用response.urljoin(url)结果为:http://www.example.com/a/b/index.html
Spider开发流程
- 从那些页面开始爬取
- 对于一个已经下载的页面,获取其中那些数据
- 爬取完当前页面后,接下来爬取那些页面
实现一个Spider需要完成一下四部
- 继承scrapy.Spider
- 为Spider取名
- 设定起始爬取点
- 实现页面解析函数
继承scrapy.Spider
scrapy框架提供一个Spider类,编写的Spider需要继承他
import scrapy
class BooksSpider(scrapy.Spider):
为Spider命名
name为唯一标示
class BooksSpider(scraoy.Spider)
name = "books"
设定爬取的起点
通过start_urls来设定起始爬取点
start_urls = ['http://books.toscrape.com']
Spider基类的start_requests方法帮助我们构造并提交了Request对象,
原理:
- 起始下载请求是由Scrapy引擎调用Spider对象start_requests方法提交,引擎自动调用提交
- 在start_requsests方法中,self.start.urls便是我们定义的起始点,对其进行迭代,用迭代的每个url作为参数调用make_requests_from_url方法
- 在make_requests_from_url方法中,真正构造request对象代码使用url和dont_filter参数构造request对象
- 构造request对象并没有传递callback参数来指定页面解析函数,因此会默认将parse方法作为页面解析函数
- 起始爬去点可能有多个,start_requests方法需要返回一个可迭代对象,其中每一个元素是一个request对象
由于下载请求是由start_request方法产生的。可以重写start_request方法,直接构造并提取爬去点的request对象。例如在:想为request添加特定的HTTP请求头部,或想为request指定特定的页面解析函数
#实现start_request方法定义起始爬取点的实例
class BooksSpider()
def start_requests(self):
yield scrapy.Request('http://books.toscrape.com/',
callback=self.parse_book,
headers={'User-Agent':'Mozilla/5.0'},
dont_filter=True)
#改用parse_book作为回调函数
def parse_book(response):
实现页面解析函数
页面解析函数也就是构造request对象时调用callback参数指定的回调函数(默认parse方法)。
它完成一下步骤
- 使用选择器提取页面中的数据,将数据封装后(item或字典)提交给Scrapy引擎
使用选择器或LinkExtractor提取页面中的链接,用其构造新的request对象并提交给Scrapy引擎(下载链接页面)
一个页面范湖多个链接,因此页面解析函数必须返回一个迭代对象(通常被实现为一个生成器函数),每次迭代返回一项数据(item 字典)或者一个request对象