爬虫项目来自scrapy官网,解析方法由scrapy自带的css解析和xpath解析。下附scrapy官网链接。
建议在有些前端基础的条件下查看这篇博客。
文章目录
一.scrapy简单介绍
scrapy是爬虫的框架,使用scrapy可以编写高效的大型爬虫,安装方法可以通过pip install scrapy来进行安装。
1.scrapy框架结构解析
scrapy有7项核心组件,我们需要了解他们的功能和运行流程。
引擎(Engine):是scrapy的“大脑”,帮助我们高效爬取并行处理数据的。
调度器(Scheduler):调度器接受引擎发过来的请求,按照先后顺序,压入列队中,同时去除重复的请求。
下载器(Downloader):下载器用于下载网页内容,并返回给爬虫,就是scrapy中的Request组件。
爬虫(Spiders):用于从特定的网页中提取需要的信息,对提取出的链接,可以发起下一次请求。
项目(Item Pipelines):项目管道负责处理爬虫从网页中抽取出的实体,并且保存成文件或存入数据库中。
另外还有下载器中间件(Downloader Middlewares)和 爬虫中间体(Spider Middlewares )就不过多介绍了,详情可以查看官网链接。
- scrapy运行流程解析
其中Spiders和pipeline 是需要我们去修改的,其他组件无需修改,框架已写好
- 首先,引擎根据我们填写的域名(例如,要爬取豆瓣,则域名为 douban.com )找到相应的Sipders组件,然后Spiders组会对爬取的url进行发送请求,发起的信息由绿色的线先后传入到调度器,并在调度器中进行去重操作。
- 并根据请求的传入顺序,Scheduler会将请求再发给引擎,再由引擎发送给下载器。其中Downloader相当于requests方法,对网页真正发起请求,请求过后不论成功失败都有一个返回,也由Downloader接受返回信息。(Downloader Middlewares)是一个下载中间件,可以起到一个过滤的作用。
- 返回后的数据交给引擎再交给Spiders.
- Spiders后有两个方向,其中一个是items最终传入的是Item Pipeline,对返回数据对实体化操作,进行文件保存等。
- 第二个是Requests,其中反映了框架的优势,不需要再次编写requests的条件。
2. scrapy爬虫目录结构解析
- 打开终端,再当前目录下创建了名为quotes的quotes项目
$ scrapy startproject quotes
- 并且根据提示进入quotes文件夹内
$ cd quotes
- 再进入spiders文件夹内
$cd spiders
- 创建quote_css.py 爬虫,
$ scrapy genspider quote_css "quotes.toscrape.com"
,其中"quotes.toscrape.com"为要爬取的网页的域名,例如,豆瓣的域名为"douban.com",会影响scrapy里的基本设置,最好根据需要填写。(注意:一个项目里可以包含多个Spiders,例如$ scrapy genspider quote_xpath "quotes.toscrape.com"
再同一个项目内创建了quote_xpath.py爬虫。
5.调用爬虫,scrapy框架书写的爬虫,不能直接运行,需要在终端,在quotes/quotes 目录下 $scrapy crawl quote_css
运行。
6.将返回内容保存为json文件,同样也需要在quotes/quotes 目录下 $ scrapy crawl quote_css -o quotes.json
二、实战案例:quotes信息爬取
用scrapy自带的css和xpath来解析网页,目标网页是http://quotes.toscrapy.com/,爬取目标是网页中的名言,作者,和标签,即图中箭头所指的三个部分
1.方法一:使用css解析数据
css主要是通过css来确定位置
打开quote_css.py文件,默认内容为,其中我们需要改写parse解析方法,parse第一次请求内容是对start_urls发起的,且是默认发起的,不需要我们再去编写requests。我们需要关注的是数据本身,怎么从返回取出我们想要的结果。
目标:爬取目标网站的quote,author,tag,爬取结果保存为json文件,并且找到文末的next链接,一直跳转爬取
基本想法:找到quote, author,tag所在html中的位置,并找规律
import scrapy
class QuoteCssSpider(scrapy.Spider):
name = 'quote_css'
allowed_domains = ['quotes.toscrape.com']#域名
start_urls = ['http://quotes.toscrape.com/']
def parse(self, response):
pass
1.首先利用开发者工具可以发现:每页有10条quote,每段quote都在class属性为quote的div标签下,可以利用 response.css(‘div.quote’)获取。
为了更好的了解scrapy是如何去数的,可以使用shell启动scrapy 终端,$ scrapy shell url表示我们要爬取的网页, scrapy shell http://quotes.toscrape.com/
,返回的reponse为scrapy的html对象,验证class属性为quote的div标签下是否为quotes
response.css('div.quote').getall()
response.css('div.quote').get()
结果如下图所示
其中getall()返回的是满足条件的所有值,返回的是列表
get()返回的满足条件的第一个值
2 依次在div标签下找到text内容,author作者和tag标签的位置,并取出里面的文本内容.由开发者工具我们可以看到,text内容在div下一节的class属性为text的span标签下,先另quote为第一个div标签,再以此为节点向下探,可以通过quote.css('span.text::text')
取得,并将取出的数据依次命名为text,author,tag,可以在scrapy shell中取得验证,结果如图所示
其中:text()表示取出其中的文本内容
同理可以取出author和tag中的内容,author在div的第二个span标签下的small标签内,其中small 的 class属性为author;tag在div的div标签下的多个标签内,其中a的class属性为tag,验证结果如下,数据解析成功
3.为了将取出的数据反映在终端上,可以使用yield.,显示结果如下
yield{'text':text, 'author':author,'tag':tag}
4.到此我们已经完整地取出了一页的内容,之后需要实现的页面的跳转,要求需要在html中获取下一页的链接,(或者根据url自己找规律)并再链接发送请求
由图可以发现,下一页的链接在class属性为next的li标签下的a标签内,且发现链接是不完整的需要我们自己补全。取出内容,命名为next_url
response.css('li.next>a::attr(href)').get()
scrapy提供了补全url的方法,urljoin()
请求补全后的链接代码可以写为scrapy.Request(response.urljoin(next_url))
quote_css.py中的完整代码
import scrapy
class QuoteCssSpider(scrapy.Spider):
name = 'quote_css'
allowed_domains = ['quotes.toscrape.com']#域名
start_urls = ['http://quotes.toscrape.com/']
def parse(self, response):
quotes=response.css('div.quote')
#寻找class属性为quote的div标签
for quote in quotes:
text=quote.css('span.text::text').get()
#从quote所在的div节点往下class属性为text的span标签,:text表示取出其中的文字
#get()是将html内容转化为str
author=quote.css('small.author::text').get()
#从quote所在的div节点往下class属性为author的small标签,并取出其中的文字
tag=quote.css('div.tags > a.tag::text').getall()
yield {
'text':text,
'author':author,
'tag':tag
}
#找到下一页的url继续爬取内容
next_url=response.css('li.next>a::attr(href)').get()
if next_url is not None:
yield scrapy.Request(response.urljoin(next_url))
在终端输入$ scrapy crawl quote_css
运行爬虫,输出结果为:
爬取成功,如果要将爬取结果保存为json文件,可以在终端输入$ scrapy crawl quote_css -o quotes.json
2.方法二:使用xpath来解析数据
目标:爬取目标网站的quote,author,tag,爬取结果保存为csv文件,并且找到文末的next链接,一直跳转爬取
步骤:
1.利用开发者工具找到需要爬取的text,author,tag所在节点的位置
2.利用scrapy验证位置
3.完整爬取一页的代码,运行查错
4.若3运行没有出错,爬取下一页的链接,并发送请求,运行查错
5.修改pipeline,item,将输出文件保存为csv文件,运行查错
quote_xpath.py的完整代码
注意tag取出数据是为多个字符串组成的列表,因后续保存的需要,因转变为一项内容,可以像下面代码中操作,也可以直接在外面套[],使之成为外面大括号内的第零项
import scrapy
from quotes.items import QuotesItem
class QuoteXpathSpider(scrapy.Spider):
name = 'quote_xpath'
allowed_domains = ['quotes.toscrape.com']
start_urls = ['http://quotes.toscrape.com/']
def parse(self, response):
items=[]
quotes=response.xpath('//div[@class="quote"]')
for quote in quotes:
item = QuotesItem()
text=quote.xpath('./span/text()').extract_first()
author=quote.xpath('./span/small[@class="author"]/text()').extract_first()
tag=quote.xpath('.//div[@class="tags"]/a[@class="tag"]/text()').extract()
item['text']=text
item['author']=author
item['tag']=[[i.strip() for i in tag]]
items.append(item)
yield item
next_url=response.xpath('//li[@class="next"]/a/@href').extract_first()
if next_url is not None:
next_url=response.urljoin(next_url)
yield scrapy.Request(next_url)
items.py的完整代码
对items进行了修改,左边为我们所需要的数据,右边为固定写法
import scrapy
class QuotesItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# pass
text=scrapy.Field()
author=scrapy.Field()
tag=scrapy.Field()
pipelines.py的完整代码
在传递的item中取出所需要的text, author,tag使用pandas模块将数据以追加方式写入quotes.csv文件
注意:
1.最后的return不能少,不然会报错
2.在将字典转换为DataFrame类型时,要加标签,不然会报错
3.不能直接将item转变为DataFrame类型
4.最重要的是,必须要修改settings中的一项才能保存!!!
import pandas as pd
class QuotesPipeline:
def process_item(self, item, spider):
df=pd.DataFrame({'text':item['text'],'author':item['author'],'tag':item['tag']},index=[0])
df.to_csv('./quotes.csv',mode='a+',encoding='utf8',index=False,header=False)
return item
必须要将settings中的ITEM_PIPELINES取消注释才能保存
最后在终端运行$scrapy crawl quote_xpath
命令检查输出
最后输出结果如下
总结
scrapy 框架在进行大型爬取工作时比较方便,scrapy内部有自己的解析工具,运行效率较高。掌握scrapy爬虫的前提应该需要了解scrapy各组件的功能和实际工作时的搭配。