scrapy数据建模与请求
时间:2023-3-1 00:00 作者:wen 分类: Python
一、数据建模
通常在做项目的过程中,在items.py中进行数据建模
-
为什么建模
- 定义item即提前规划好那些字段需要抓,防止手误,因为定义好之后,在运行过程中,系统会自动检查
- 配合注释一起可以清晰的知道要抓取那些字段,没有定义的字段不能抓取,在目标字段少的时候可以使用字典代替
- 使用 scrapy的一些特定组件需要item做支持,如scrapy的ImagePipeline管道类,百度收索了解更多
-
如何建模
在items.py文件中定义要提取的字段:class MyspiderItem(scrapy.Item): # define the fields for your item here like: title = scrapy.Field() # 网站标题 href = scrapy.Field() # 标题链接 pass
-
如何使用模板类
模板类定义以后需要在爬虫中导入并且实例化,之后的使用方式和使用字典相同:job.py
import scrapy
from myspider.items import MyspiderItem
class WenxkSpider(scrapy.Spider):
name = 'wenxk'
allowed_domains = ['wenxk.top']
start_urls = ['http://wenxk.top/']
def parse(self, response):
node_list = response.xpath("//div[@class='views-row']")
for node in node_list:
temp = MyspiderItem() # 实例化后可直接使用
temp['title'] = node.xpath('./article/header/h2/a/span/text()').extract_first()
temp['href'] = node.xpath('./article/header/h2/a/@href')[0].extract()
# xpath方法返回的是选择器对象列表,extract()用于从选择器对象中提取数据
# xpath结果为只含有一个结果的列表,可以使用extract_first(),没有结果返回None,如果为多个使用extract()
yield temp
pass
注意:
from myspider.items import MyspiderItem这一行代码中 注意item的正确导入路径,忽悠pycharm标记的错误
- python中的导入路径要诀:从哪里开始运行,就从哪里开始导入
- 开发流程总结
- 创建项目
scrapy startproject 项目
- 明确目标
- 在items.py文件中进行建模
- 创建爬虫
- scrapy genspider 爬虫名 允许的域
- 修改 start_urls 检查修改 allowed_domains 编写解析方法
- 保存数据
- 在pipeline.py文件中定义对数据处理的管道
- 在settings.py文件中注册启用管道
- 创建项目
二、翻页请求的思路
- 找到下一页的url路径
- 构造url地址的请求对象,传递给引擎
三、构造Request对象,并发送请求
- 实现方法
- 确定url地址
- 构造请求,scrapy.Request(url,callback)
- callback:指定解析函数名称,表示该请求返回的相应使用哪一个函数进行解析
- 把请求交给引擎:yield scrapy.Request(url,callback)
- 网易招聘爬虫
通过爬取网易招聘的页面的信息,学习如何实现翻页请求
地址:https://hr.163.com/position/list.do
思路分析:
1、获取页面的数据
2、寻找下一页的地址,进行翻页,获取数据
注意:
1、可以在setting中设置RoBots协议,False表示忽略网站的robots.txt协议,默认为True
# Obey robots.txt rules
ROBOTSTXT_OBEY = True
2、可以在setting中设置User-Agent,scrapy发送的每一个请求地址的默认UA都是设置的这个User-Agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'
3、代码实现
# items.py
import scrapy
class WagnyiItem(scrapy.Item):
# define the fields for your item here like:
name = scrapy.Field() # 岗位名称
link = scrapy.Field() # 链接
department = scrapy.Field() # 所属部门
category = scrapy.Field() # 职位类别
type = scrapy.Field() # 工作类型
address = scrapy.Field() # 工作地点
num = scrapy.Field() # 招聘人数
data = scrapy.Field() # 发布时间
pass
# job.py
import scrapy
from wagnyi.items import WagnyiItem
class JobSpider(scrapy.Spider):
name = 'job'
allowed_domains = ['163.com']
start_urls = ['https://hr.163.com/position/list.do']
def parse(self, response):
# 提取数据
# 获取所以职业节点列表
node_list = response.xpath('//*[@class="position-tb"]/tbody/tr')
# 遍历节点列表
for num, node in enumerate(node_list):
# 设置过滤条件,将目标节点获取出来
if num % 2 == 0:
item = WagnyiItem()
item['name'] = node.xpath('./td[1]/a/text()').extract_first()
# response.urlJoin() 用于拼接相对路径的url,可以理解为自动补全
item['link'] = response.urljoin(node.xpath('./td[1]/a/@href').extract_first())
item['department'] = node.xpath('./td[2]/text()').extract_first()
item['category'] = node.xpath('./td[3]/text()').extract_first()
item['type'] = node.xpath('./td[4]/text()').extract_first()
item['address'] = node.xpath('./td[5]/text()').extract_first()
item['num'] = node.xpath('./td[6]/text()').extract_first().strip()
item['data'] = node.xpath('./td[7]/text()').extract_first()
yield item
# 模拟翻页
part_url = response.xpath('/html/body/div[2]/div[2]/div[2]/div/a[last()]/@href').extract_first()
# 判断终止条件
if part_url != "javascript:void(0)":
next_url = response.urljoin(part_url)
# 构建请求对象,并返回给引擎
yield scrapy.Request(url=next_url, callback=self.parse)
pass
# pipelines.py
import json
from itemadapter import ItemAdapter
class WagnyiPipeline:
def __init__(self):
self.file = open('wangyi.json','w')
def process_item(self, item, spider):
item = dict(item)
str_data = json.dumps(item,ensure_ascii=False) + ',\n'
self.file.write(str_data)
return item
def __del__(self):
self.file.close()
- scrapy.Request的更多的参数
scrapy.Request(url[,callback,method='GET',headers,body,cookies,meta,dont_filter=False])
参数解释- 中括号里的参数为可选参数
- callback:表示当前的url的响应交给那个函数去处理
- mete:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延时,请求深度
- dont_filter:默认为False,会过滤请求的URL地址,即请求过的url地址不会继续请求,对需要重复请求的URL地址可以把它设置为True,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
- method请求POST或GET请求
- headers:接收一个字典,其中不包括cookie
- cookies:接收一个字典,专门放置cookies
- body:接收json字符串,为POST的数据,发送payload_post请求时使用
四、meta参数的使用
meta的作用:meta可以实现数据在不同的解析函数中的传递
在爬虫文件的parse方法中,提取详细页增加之前callback指定的parse_detail函数:
# job.py
import scrapy
from wagnyi.items import WagnyiItem
class JobSpider(scrapy.Spider):
name = 'job'
allowed_domains = ['163.com']
start_urls = ['https://hr.163.com/position/list.do']
def parse(self, response):
# 提取数据
# 获取所以职业节点列表
node_list = response.xpath('//*[@class="position-tb"]/tbody/tr')
# 遍历节点列表
for num, node in enumerate(node_list):
# 设置过滤条件,将目标节点获取出来
if num % 2 == 0:
item = WagnyiItem()
item['name'] = node.xpath('./td[1]/a/text()').extract_first()
# response.urlJoin() 用于拼接相对路径的url,可以理解为自动补全
item['link'] = response.urljoin(node.xpath('./td[1]/a/@href').extract_first())
item['department'] = node.xpath('./td[2]/text()').extract_first()
item['category'] = node.xpath('./td[3]/text()').extract_first()
item['type'] = node.xpath('./td[4]/text()').extract_first()
item['address'] = node.xpath('./td[5]/text()').extract_first()
item['num'] = node.xpath('./td[6]/text()').extract_first().strip()
item['data'] = node.xpath('./td[7]/text()').extract_first()
yield scrapy.Request(url=item['link'], callback=self.parse_detail,meta={'item': item})
# 模拟翻页
part_url = response.xpath('/html/body/div[2]/div[2]/div[2]/div/a[last()]/@href').extract_first()
# 判断终止条件
if part_url != "javascript:void(0)":
next_url = response.urljoin(part_url)
# 构建请求对象,并返回给引擎
yield scrapy.Request(url=next_url, callback=self.parse, meta={'item': item})
pass
def parse_detail(self, response):
# 获取之前传入的item
item = response.meta['item']
print(item)
特别注意:
1、meta参数是一个字典
2、meta字典中有一个固定的键proxy,表示代理ip。
标签: 爬虫