1. 数据建模
1.1 为何要建模
- 在
item
中提前定义好需要抓取的内容,防止在爬虫文件中误写 - 提前定义加注释和明确目标
1.2 如何建模
在item.py
中
class MyspiderItem(scrapy.Item):
name = scrapy.Field() # 讲师的名字
title = scrapy.Field() # 讲师的职称
desc = scrapy.Field() # 讲师的介绍
1.3 如何使用建好的模
在爬虫文件中在
from myspider.items import MyspiderItem # 1. 导入Item,注意路径
...
def parse(self, response)
item = MyspiderItem() # 2. 实例化后可直接使用
item['name'] = node.xpath('./h3/text()').extract_first()
item['title'] = node.xpath('./h4/text()').extract_first()
item['desc'] = node.xpath('./p/text()').extract_first()
print(item)
yield item # 3. 传递给pipeline
1.4 开发基本流程总结
- 开启项目:
scrapy startproject CSDN
- 创建爬虫模板:先
cd CSDN
,然后scrapy genspider csdn csdn.net
- 明确爬虫目标,修改
item.py
文件- 完善爬虫文件:
csdn.py
start_url
- 完善
parse
方法- 保存数据:修改
pipelines.py
和开启setting.py
中参数
2. Request请求的应用–翻页、同时爬取其他页面
2.1 如何实现翻页
- 找到下一页url
- 构造翻页请求对象,传递给引擎
2.2 实现方法
- 确定下一页url
- 构造请求对象:
scrapy.Request(url, callback=self.parse)
- 提交给引擎:
yield scrapy.Request(url, callback=self.parse)
2.3 示例
爬取暨南大学学院教师基本信息
import scrapy
from jnuteachers.items import JnuteachersItem
class JnuSpider(scrapy.Spider):
name = 'jnu'
allowed_domains = ['jnu.edu.cn']
start_urls = ['http://xxxy2016.jnu.edu.cn/Category_96/Index.aspx']
flag = 0
def parse(self, response):
ls = response.xpath('//*[@id="techerList"]/div[2]/ul/li')
for tmp in ls:
item = JnuteachersItem()
item['name'] = tmp.xpath('./span[1]/a/text()').extract_first()
item['link'] = response.urljoin(tmp.xpath('./span[1]/a/@href').extract_first())
item['level'] = tmp.xpath('./span[2]/text()').extract_first()
item['direction'] = tmp.xpath('./span[3]/text()').extract_first()
item['email'] = tmp.xpath('./span[4]/text()').extract_first()
part_url = response.xpath('//*[@id="pe100_page_通用信息列表_领导式"]/div/a[4]/@href').extract_first()
print('part_url:',part_url)
last_url = response.xpath('//*[@id="pe100_page_通用信息列表_领导式"]/div/a[5]/@href').extract_first()
print('last_url:',last_url)
print(JnuSpider.flag)
if (part_url != last_url) or (JnuSpider.flag == 0):
if part_url == last_url:
JnuSpider.flag += 1
next_url = 'http://xxxy2016.jnu.edu.cn/Category_96/' + part_url
yield scrapy.Request(
url = next_url,
callback= self.parse
)
2.4 Request参数详解
scrapy.Request(url[,callback,method="GET",headers,body,cookies,meta,dont_filter=False])
参数解释
- 中括号里的参数为可选参数
- callback:表示当前的url的响应交给哪个函数去处理
- meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等
- dont_filter:默认为False,会过滤请求的url地址,即请求过的url地址不会继续被请求,对需要重复请求的url地址可以把它设置为Ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
- method:指定POST或GET请求
- headers:接收一个字典,其中不包括cookies
- cookies:接收一个字典,专门放置cookies
- body:接收json字符串,为POST的数据,发送payload_post请求时使用
2.5 Request中meta参数的使用
可以用于解析当前页面中链接的其他页面数据
注意:meta参数是一个字典meta={“item”:item}
def parse(self,response):
...
yield scrapy.Request(detail_url, callback=self.parse_detail,meta={"item":item})
...
def parse_detail(self,response):
#获取之前传入的item
item = resposne.meta["item"]
import scrapy
from jnuteachers.items import JnuteachersItem
class JnuSpider(scrapy.Spider):
name = 'jnu'
allowed_domains = ['jnu.edu.cn']
start_urls = ['http://xxxy2016.jnu.edu.cn/Category_96/Index.aspx']
flag = 0
def parse(self, response):
ls = response.xpath('//*[@id="techerList"]/div[2]/ul/li')
print(len(ls))
for tmp in ls:
# 使用建立的模板对象
item = JnuteachersItem()
item['name'] = tmp.xpath('./span[1]/a/text()').extract_first()
item['link'] = response.urljoin(tmp.xpath('./span[1]/a/@href').extract_first())
item['level'] = tmp.xpath('./span[2]/text()').extract_first()
item['direction'] = tmp.xpath('./span[3]/text()').extract_first()
item['email'] = tmp.xpath('./span[4]/text()').extract_first()
print(item)
# 对链接其他页的请求构造及传递给引擎
yield scrapy.Request(url=item['link'], callback=self.detail_url,meta={'item':item})
# 获取下一页和尾页的地址
part_url = response.xpath('//*[@id="pe100_page_通用信息列表_领导式"]/div/a[4]/@href').extract_first()
last_url = response.xpath('//*[@id="pe100_page_通用信息列表_领导式"]/div/a[5]/@href').extract_first()
# 对翻页的处理以及尾页的处理
if (part_url != last_url) or (JnuSpider.flag == 0):
if part_url == last_url:
JnuSpider.flag += 1
next_url = 'http://xxxy2016.jnu.edu.cn/Category_96/' + part_url
# 对下一页的请求构造对象及传递给引擎
yield scrapy.Request(
url = next_url,
callback= self.parse
)
# 处理链接的其他页面抓取
def detail_url(self,response):
item = response.meta['item']
item['exp'] = response.xpath('//*[@id="Education"]/div[2]/p/span/text()').extract()
item['result'] = response.xpath('//*[@id="Winning"]/div[2]/p/span/text()').extract()
print(item)
yield item