【零基础学爬虫】第五章:scrapy数据解析实战(二)
一、项目准备
1.创建工程
scrapy startproject qiubaiPro
2.创建爬虫文件
需求:爬取糗事百科中“段子”栏中的数据:https://www.qiushibaike.com/text/,解析作者名称+段子内容。
cd qiubaiPro
scrapy genspider qiubai https://www.qiushibaike.com/text/
3.修改配置文件
ROBOTSTXT_OBEY = False
# 显示指定类型的日志信息
LOG_LEVEL = 'ERROR'
# 修改UA伪装
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'
二、程序编写
1.编写程序
import scrapy
class QiubaiSpider(scrapy.Spider):
name = 'qiubai'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.qiushibaike.com/text/']
def parse(self, response):
# 解析作者的名称+段子内容
# 这里的xpath和etree.xpath不是同一个方法,但是用法几乎一样
div_list = response.xpath('//div[@class="col1 old-style-col1"]/div')
for div in div_list:
# xpath返回的是列表,但是列表元素一定是selector类型的对象
# extract 可以将selector对象中data参数存储的字符串提取出来
author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
# 或者用extract_first,作用是将列表中第0个列表元素对应的selector进行extract操作。
# 列表中只有一个列表元素的时候,可以用extract_first
# author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
# 列表调用了extract后,表示将列表中每一个selector对象中data对应的字符串提取了出来
content = div.xpath('./a[1]/div/span//text()').extract() # 因为文本中有<br>标签,要用//
# 将列表转换为字符串
content = ''.join(content)
print(author, content)
break
注意:scrapy中的xpath返回的列表中是一个Selector对象,如需转换成字符串,应该用extract把Selector中data对应的字符串取出来。
2.执行程序
scrapy crawl qiubai
三、持久化存储
1.基于终端指令存储
①在上面代码的基础上,把数据存在一个字典中。
import scrapy
class QiubaiSpider(scrapy.Spider):
name = 'qiubai'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.qiushibaike.com/text/']
# 基于终端的存储
def parse(self, response):
# 解析作者的名称+段子内容
# 这里的xpath和etree.xpath不是同一个方法,但是用法几乎一样
div_list = response.xpath('//div[@class="col1 old-style-col1"]/div')
all_data = []
for div in div_list:
# xpath返回的是列表,但是列表元素一定是selector类型的对象
# extract 可以将selector对象中data参数存储的字符串提取出来
author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
# author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
# 列表调用了extract后,表示将列表中每一个selector对象中data对应的字符串提取了出来
content = div.xpath('./a[1]/div/span//text()').extract() # 因为文本中有<br>标签,要用//
# 将列表转换为字符串
content = ''.join(content)
dic = {
'author' : author,
'content': content
}
all_data.append(dic)
return all_data
②在终端输入命令进行存储
scrapy crawl qiubai -o ./qiubai.csv
③注意事项
- 要求:只可以将parse方法的返回值存储到本地的文本文件中
- 注意:持久化存储对应的文本文件的类型只可以为:'json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle
- 指令:scrapy crawl xxx -o filePath
- 好处:简介高效便捷
- 缺点:局限性比较强(数据只可以存储到指定后缀的文本文件中)
2.基于管道存储
①编码流程:
- 数据解析
- 在item类中定义相关的属性 (修改items.py)
- 将解析的数据封装存储到item类型的对象
- 将item类型的对象提交给管道进行持久化存储的操作
- 在管道类的process_item中要将其接受到的item对象中存储的数据进行持久化存储操作
- 在配置文件中开启管道
②修改items.py文件
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class QiubaiproItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
author = scrapy.Field()
content = scrapy.Field()
pass
③修改pipelines.py文件
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
class QiubaiproPipeline:
fp = None
# 重写父类的一个方法,该方法只在开始爬虫的时候被调用一次
def open_spider(self,spider):
print("开始爬虫.......")
self.fp = open('./qiubai.txt','w',encoding='utf-8')
# 专门用来处理item类型对象的
# 该方法可以接收爬虫文件提交过来的item对象
# 该方法每接收到1个item就会被调用一次
def process_item(self, item, spider):
author = item['author']
content = item['content']
self.fp.write(author+':'+content+'\n')
return item
def close_spider(self,spider):
print("结束爬虫!!")
self.fp.close()
④修改settings.py文件
# 开启管道,把文件中的注释删掉
ITEM_PIPELINES = {
'qiubaiPro.pipelines.QiubaiproPipeline': 300,
}
# 300表示的是优先级,数值越小优先级越高
⑤完整主程序
import scrapy
from qiubaiPro.items import QiubaiproItem
class QiubaiSpider(scrapy.Spider):
name = 'qiubai'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.qiushibaike.com/text/']
# 基于管道的存储
def parse(self, response):
# 解析作者的名称+段子内容
# 这里的xpath和etree.xpath不是同一个方法,但是用法几乎一样
div_list = response.xpath('//div[@class="col1 old-style-col1"]/div')
all_data = []
for div in div_list:
# xpath返回的是列表,但是列表元素一定是selector类型的对象
# extract 可以将selector对象中data参数存储的字符串提取出来
author = div.xpath('./div[1]/a[2]/h2/text()')[0].extract()
# author = div.xpath('./div[1]/a[2]/h2/text()').extract_first()
# 列表调用了extract后,表示将列表中每一个selector对象中data对应的字符串提取了出来
content = div.xpath('./a[1]/div/span//text()').extract() # 因为文本中有<br>标签,要用//
# 将列表转换为字符串
content = ''.join(content)
# 将解析的数据封装到item类型的对象中
item = QiubaiproItem()
item['author'] = author
item['content'] = content
# 将item提交给了管道
yield item