1.明确任务

目标网站:http://fz.people.com.cn/skygb/sk/index.php/Index/seach

抓取任务:抓取近五年某关键词(例如"能源"、”大数据“等)的搜索结果,抓取内容包括项目编号、项目名称、学科分类等十一个字段。

2.网站分析

利用Fiddler工具分析,输入关键词,指定年份后,点击搜索,针对有多页码搜索结果点击下一页,发现此过程共包括一个POST请求和一个GET请求;其中,指定关键词和年份点击搜索的过程为POST请求,点击下一页的过程为GET请求。

POST请求参数:

formdata = {
'xmname': '',
'xktype': '',
'xmtype': '',
'cglevel': '',
'cbdate ': '',
'cgxs': '',
'lxtime': '',
'ssxt': '',
'zyzw': '',
'dwtype': '',
'jxdata': '',
'szdq': '',
'pznum': '',
'cgname': '',
'jxnum': '',
'cbs': '',
'xmleader': '',
'hj': '',
'gzdw': '',
'zz': ''
}

POST请求目标URL:http://fz.people.com.cn/skygb/sk/index.php/Index/seach

GET请求只需要指定参数p即可,因此构造GET请求url为:

n_url = self.url + '?' + 'xmname={}&p={}'.format(formdata['xmname'], self.page)

其中,xmname为搜索关键词,p为第几页的页码。

3.代码编写

3.1 创建scrapy爬虫项目

创建项目,名为ProSearch,使用命令:

scrapy startproject ProSearch http://fz.people.com.cn

3.2 明确抓取字段

创建爬虫项目后,编写items.py文件,明确待抓取的字段

# -*- coding: utf-8 -*-
import scrapy
class ProsearchItem(scrapy.Item): # 关键词
keyword = scrapy.Field()
# 项目编号
pronums = scrapy.Field()
# 项目类别
protype = scrapy.Field()
# 学科类别
subtype = scrapy.Field()
# 项目名称
proname = scrapy.Field()
# 立项时间
protime = scrapy.Field()
# 负责人
leaders = scrapy.Field()
# 工作单位
workloc = scrapy.Field()
# 单位类别
orgtype = scrapy.Field()
# 所在省市
provloc = scrapy.Field()
# 所属系统
systloc = scrapy.Field()

3.3 生成爬虫文件

在cmd窗口进入到ProSearch项目后,生成爬虫文件。使用命令:

scrapy genspider SearchPro

3.4 编写爬虫逻辑

生成爬虫文件后,来到spiders文件夹下的SearchPro.py文件,开始辨写爬虫逻辑。

# -*- coding: utf-8 -*-
import scrapy
from ProSearch.items import ProsearchItem class SearchproSpider(scrapy.Spider): name = 'SearchPro' # 爬虫名称
allowed_domains = ['fz.people.com.cn']
# start_urls = ['http://fz.people.com.cn/skygb/sk/index.php/Index/seach']
page = 1 # 指定检索关键词
keywords = ['可持续', '互联网', '大数据', '能源']
# 角标
index = 0
# 年份
years = 2018 # POST提交参数
formdata = {
'xmname': '',
'xktype': '',
'xmtype': '',
'cglevel': '',
'cbdate ': '',
'cgxs': '',
'lxtime': '',
'ssxt': '',
'zyzw': '',
'dwtype': '',
'jxdata': '',
'szdq': '',
'pznum': '',
'cgname': '',
'jxnum': '',
'cbs': '',
'xmleader': '',
'hj': '',
'gzdw': '',
'zz': ''
} # 参数提交的url
url = "http://fz.people.com.cn/skygb/sk/index.php/Index/seach" def start_requests(self):
"""
POST请求实现一般是重写start_requests函数,指定第一个关键词为默认检索关键词
:return:
"""
self.formdata['xmname'] = '可持续'
self.formdata['lxtime'] = str(self.years)
yield scrapy.FormRequest(
url=self.url,
formdata=self.formdata,
callback=self.parse,
meta={'formdata': self.formdata}
) def parse(self, response):
"""
解析数据
:param response:
:return:
"""
if response.meta['formdata']:
formdata = response.meta['formdata'] # 每行数据所在节点
try:
node_list = response.xpath("//div[@class='jc_a']/table/*")[1:]
except:
print("关键词‘{}’无搜索结果!".format(formdata['xmname']))
for node in node_list:
# 提取数据
item = ProsearchItem()
# 关键词
item['keyword'] = formdata['xmname']
# 项目编号
item['pronums'] = node.xpath('./td[1]/span/text()').extract_first()
# 项目类别
item['protype'] = node.xpath('./td[2]/span/text()').extract_first()
# 学科类别
item['subtype'] = node.xpath('./td[3]/span/text()').extract_first()
# 项目名称
item['proname'] = node.xpath('./td[4]/span/text()').extract_first()
# 立项时间
item['protime'] = node.xpath('./td[5]/span/text()').extract_first()
# 负责人
item['leaders'] = node.xpath('./td[6]/span/text()').extract_first()
# 工作单位
item['workloc'] = node.xpath('./td[8]/span/text()').extract_first()
# 单位类别
item['orgtype'] = node.xpath('./td[9]/span/text()').extract_first()
# 所属省市
item['provloc'] = node.xpath('./td[10]/span/text()').extract_first()
# 所属系统
item['systloc'] = node.xpath('./td[11]/span/text()').extract_first()
yield item # 匹配下一页的数据
if '下一页' in response.xpath("//div[@class='page clear']/a").extract():
self.page += 1
n_url = self.url + '?' + 'xmname={}&p={}'.format(formdata['xmname'], self.page)
yield scrapy.Request(url=n_url, callback=self.parse, meta={'formdata': formdata}) # 匹配其他年份的数据
searcy_year = int(formdata['lxtime'])
if not searcy_year <= 2014:
searcy_year -= 1
formdata['lxtime'] = str(searcy_year)
print("检索关键词:{}!".format(formdata['xmname']))
yield scrapy.FormRequest(
url=self.url,
formdata=formdata,
callback=self.parse,
meta={'formdata': formdata}
)
# 其他关键词搜索
else:
self.index += 1
if not self.index > len(self.keywords)-1:
keyword = self.keywords[self.index]
print("更新检索关键词为:{}".format(keyword)) formdata['xmname'] = keyword
formdata['lxtime'] = str(self.years) yield scrapy.FormRequest(
url=self.url,
formdata=formdata,
callback=self.parse,
meta={'formdata': formdata}
)

3.5 编写数据保存逻辑

本项目用excel对数据进行保存。在pipelines.py文件中编写数据保存的逻辑。

# -*- coding: utf-8 -*-
from openpyxl import Workbook class ProsearchPipeline(object): def __init__(self):
# 创建excel表格保存数据
self.workbook = Workbook()
self.booksheet = self.workbook.active
self.booksheet.append(['关键词', '项目编号', '项目类别', '学科类别', '项目名称', '立项时间', '负责人', '工作单位', '单位类别', '所在省市', '所属系统']) def process_item(self, item, spider): DATA = [
item['keyword'], item['pronums'], item['protype'], item['subtype'], item['proname'], item['protime'], item['leaders'], item['workloc'], item['orgtype'], item['provloc'], item['systloc']
] self.booksheet.append(DATA)
self.workbook.save('./data/ProSearch.xls')
return item

3.6 其他细节

到此基本内容完成,设置一下settings.py文件对细节进行处理基本爬虫就可以运行了。

处理一:打开pipline通道

处理二:添加随机请求头并打开下载中间件

处理三:添加重拾、延时、log级别等

处理四:编写脚本main.py文件

scrapy默认使用命令行进行创建、生成、爬去等任务,可尝试在整个项目下编写一个main.py文件,将爬去命令添加到py文件中,直接在编辑器中F5运行。

下次每次运行main.py文件就可以直接运行了。

4.完整代码

完整代码参见github

												

最新文章

  1. 萌新笔记——linux下查看内存的使用情况
  2. javascript 原型查找 再次试探~
  3. JQuery 添加节点
  4. Python黑客编程基础3网络数据监听和过滤
  5. CF451A Game With Sticks 水题
  6. 深度神经网络结构以及Pre-Training的理解
  7. JSP页面显示乱码
  8. 增加duilib edit控件的提示功能和多种文字颜色
  9. Oracle DB 管理数据库的空间
  10. webkit常见问题汇总
  11. MEF 编程指南(五):延迟导出
  12. Path对象
  13. python3.x中如何实现print不换行
  14. 深入javascript的主流的模块规范
  15. css的三种书写方式
  16. 手动实现一个list的常用功能
  17. 一个简易的allocator
  18. Solaris 11配置IPS安装系统包(类似linux中的yum源)
  19. Android开发训练之第五章——Building Apps with Connectivity &amp; the Cloud
  20. P4596 [COCI2011-2012#5] RAZBIBRIGA

热门文章

  1. 修改List&lt;Map&lt;String, Object&gt;&gt;的值
  2. UI控件拖动失效
  3. vue cli3.3 以上版本配置vue.config.js 及反向代理操作解决跨域操作
  4. docker入门级详解
  5. Swift UIViewController中的delegate方式传值
  6. java 项目时间和服务器时间不一致
  7. 在虚拟机上的关于NFS网络文件系统
  8. 字符logo存档
  9. 单点登录 - API 认证系统 Passport(二)
  10. 「CF630C」Lucky Numbers