scrapy结合selenium抓取武汉市环保局空气质量日报
1.前言
目标网站:武汉市环境保护局(http://hbj.wuhan.gov.cn/viewAirDarlyForestWaterInfo.jspx)。scrapy对接selenium模块抓取空气质量日报数据,需要搭建selenium运行的相应环境,大概搭建方法参见:selenium基本使用;主要是模块的安装和驱动的下载与安装,windows下好像不支持Chorme的无头浏览器,但是有界面的浏览器速度会相对较慢,有条件搭建linux的,用linux下的Chorme headless驱动会快很多;其他的,像火狐等主流浏览器也有对应的驱动,环境搭建差不多,本文用的就是windows下谷歌的驱动(慢就慢点吧);Phantomjs无头浏览器好像现在不能用了。
注意:Chorme浏览器的驱动下载需要结合自己电脑的浏览器版本下载对应的驱动,不然可能驱动用不了。
2.任务分析
抓取武汉市环境保护局的空气质量日报,该网站数据是采用异步加载的;抓包分析可知,整个过程都是对同一个url进行抓取(注:这是一个点,后续编码需要考虑的);因为是用selenium点开网页,所以不需要考虑POST还是GET请求。
3.代码逻辑
3.1 创建scrapy项目
基础的项目创建、爬虫创建及创建后项目的文件结构等内容,就不一一写了,基本使用网上有很多博文,直接上正文了。
3.2 明确抓取字段
来到items.py文件,明确待抓取字段。
# -*- coding: utf-8 -*-
import scrapy class EnvprotectItem(scrapy.Item): # 日期
date = scrapy.Field()
# 点位
loca = scrapy.Field()
# SO2
SO_2 = scrapy.Field()
# NO2
NO_2 = scrapy.Field()
# 吸入颗粒
PMIO = scrapy.Field()
# CO
CO_1 = scrapy.Field()
# O3
O3_d = scrapy.Field()
# 细颗粒物
PM25 = scrapy.Field()
# 空气质量指数
AQIe = scrapy.Field()
# 首要污染物
prmy = scrapy.Field()
# AQI级别
AQIl = scrapy.Field()
# AQI类别
AQIt = scrapy.Field()
3.3 编写爬虫逻辑
到spiders文件夹下的爬虫文件中,开始编写爬虫逻辑。
从第一次selenium请求后的结果中,解析出共多少条数据,以此确定共多少个页面;
从返回的网页源代码中解析数据;
模拟点击“下一页”,获取数据后,继续解析数据,直至解析完所有页面;
selenium模拟点击操作的代码都在middlewares.py的下载中间件中编写;
scrapy会默认过滤掉重复请求(即目标url相同),我们是对同一目标url爬取,因此注意重复请求的设置。
# -*- coding: utf-8 -*-
import math
import scrapy
from EnvProtect.items import EnvprotectItem class ProtectenvSpider(scrapy.Spider):
name = 'ProtectEnv'
# allowed_domains = ['hbj.wuhan.gov.cn']
# start_urls = ['http://hbj.wuhan.gov.cn/']
page=1
pages=1
# 目标url
base_url = 'http://hbj.wuhan.gov.cn/viewAirDarlyForestWaterInfo.jspx' def start_requests(self):
yield scrapy.Request(
url=self.base_url,
callback=self.parse,
dont_filter=True, # 设置不过滤重复请求,scrapy默认过滤重复请求
meta={'index':1} # 该参数判断是否为第一次请求
) def parse(self, response):
"""
第一次请求返回结果中解析出,指定时间段(在middlewares.py文件中指定,后续介绍)内一共有多少条数据;
由于一直是对同一个页面进行爬取(翻页时url没变,数据变了),数据共多少条(页)确定一次就够了
:param response:
:return:
"""
if response.meta['index']:
counts = response.xpath("//div[@class='serviceitempage fr']/span[@class='fl']/text()").extract_first()
counts = int(counts.split(' ')[0])
self.pages = math.ceil(counts / 22) # 确定一共多少个页面 # 解析数据
node_list = response.xpath('//*[@id="tableForm"]/div/div[3]/table/tbody/tr')[1:]
for node in node_list:
item = EnvprotectItem()
item['date'] = node.xpath("./td[1]/text()").extract_first()
item['loca'] = node.xpath("./td[2]/text()").extract_first()
item['SO_2'] = node.xpath("./td[3]/text()").extract_first()
item['NO_2'] = node.xpath("./td[4]/text()").extract_first()
item['PMIO'] = node.xpath("./td[5]/text()").extract_first()
item['CO_1'] = node.xpath("./td[6]/text()").extract_first()
item['O3_d'] = node.xpath("./td[7]/text()").extract_first()
item['PM25'] = node.xpath("./td[8]/text()").extract_first()
item['AQIe'] = node.xpath("./td[9]/text()").extract_first()
item['prmy'] = node.xpath("./td[10]/text()").extract_first()
item['AQIl'] = node.xpath("./td[11]/text()").extract_first()
item['AQIt'] = node.xpath("./td[12]/text()").extract_first()
yield item # 编写爬虫停止运行逻辑
if self.page < self.pages:
self.page += 1
yield scrapy.Request(
url = self.base_url,
callback=self.parse,
dont_filter=True, # 不过滤重复请求,scrapy默认过滤重复请求
meta={'index':0}
)
3.4 编写下载中间件
selenium的所有操作的代码都写在下载中间件中。
# -*- coding: utf-8 -*-
import time
import scrapy
from selenium.webdriver.common.action_chains import ActionChains
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By from EnvProtect.settings import USER_AGENTS as ua class EnvprotectDownloaderMiddleware(object): def __init__(self):
"""
第一页时,不需要点击跳转;其他页面需要模拟点击跳转来获取数据
"""
self.index = 1 def process_request(self, request, spider): if request.url == 'http://hbj.wuhan.gov.cn/viewAirDarlyForestWaterInfo.jspx': self.driver = webdriver.Chrome() # 实例化一个谷歌浏览器
self.driver.get(request.url) # 请求页面
wait = WebDriverWait(self.driver, 30) # 等待页面数据加载,等待30s
try:
# 选择城区
wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, "iframepage"))) # 等待iframe标签出现
options = self.driver.find_element_by_xpath("//select[@id='typedictionary']/option[2]")
options.click() # 选择时间
self.driver.find_element_by_id('cdateBeginDic').send_keys('2018-11-01')
self.driver.find_element_by_id('cdateEndDic').send_keys('2019-01-20') # 点击查询
self.driver.find_element_by_xpath("//a[@href='#' and @onclick='toQuery(2);']").click()
time.sleep(5) # 指定页面
if not self.index == 1:
self.index += 1 # 第一个页面不用跳转,其他页面需要跳转过去
self.driver.find_element_by_id('goPag').send_keys(str(self.index))
self.driver.find_element_by_id('_goPag').click() # 跳转到该页面
except:
print("Error!")
self.driver.quit() # 构造返回response
html = self.driver.page_source
self.driver.quit()
response = scrapy.http.HtmlResponse(url=request.url, body=html, request=request, encoding='utf-8') return response
3.5 数据保存逻辑
在pipelines文件中编写数据保存逻辑,此处将数据保存为excel文件。
# -*- coding: utf-8 -*-
from openpyxl import Workbook class EnvprotectPipeline(object): def __init__(self):
# 创建excel表格保存数据
self.workbook = Workbook()
self.booksheet = self.workbook.active
self.booksheet.append(['日期', '检测点位', '二氧化硫',
'二氧化氮', '可吸入颗粒物', '一氧化碳',
'臭氧', '细颗粒物', '空气质量指数',
'首要污染物', 'AQI指数级别', 'AQI指数类别']) def process_item(self, item, spider): DATA = [
item['date'], item['loca'], item['SO_2'],
item['NO_2'], item['PMIO'], item['CO_1'],
item['O3_d'], item['PM25'], item['AQIe'],
item['prmy'], item['AQIl'], item['AQIt']
] self.booksheet.append(DATA)
self.workbook.save('./results.xls')
return item
3.6 其他
1.在settings.py文件中打开对应的pipe通道;
2.关闭robot.txt协议
4.完整代码
参见:github地址
scrapy结合selenium抓取武汉市环保局空气质量日报的更多相关文章
- [转]使用scrapy进行大规模抓取
原文:http://www.yakergong.net/blog/archives/500 使用scrapy有大概半年了,算是有些经验吧,在这里跟大家讨论一下使用scrapy作为爬虫进行大规模抓取可能 ...
- 在Scrapy项目【内外】使用scrapy shell命令抓取 某网站首页的初步情况
Windows 10家庭中文版,Python 3.6.3,Scrapy 1.5.0, 时隔一月,再次玩Scrapy项目,希望这次可以玩的更进一步. 本文展示使用在 Scrapy项目内.项目外scrap ...
- scrapy定时执行抓取任务
在ubuntu环境下,使用scrapy定时执行抓取任务,由于scrapy本身没有提供定时执行的功能,所以采用了crontab的方式进行定时执行: 首先编写要执行的命令脚本cron.sh #! /bin ...
- Python爬虫实战八之利用Selenium抓取淘宝匿名旺旺
更新 其实本文的初衷是为了获取淘宝的非匿名旺旺,在淘宝详情页的最下方有相关评论,含有非匿名旺旺号,快一年了淘宝都没有修复这个. 可就在今天,淘宝把所有的账号设置成了匿名显示,SO,获取非匿名旺旺号已经 ...
- selenium抓取动态网页数据
1.selenium抓取动态网页数据基础介绍 1.1 什么是AJAX AJAX(Asynchronouse JavaScript And XML:异步JavaScript和XML)通过在后台与服务器进 ...
- selenium抓取视频
今天闲着没事,用selenium抓取视频保存到本地,只爬取了第一页,只要小于等于5分钟的视频... 为什么不用requests,没有为什么,就因为有些网站正则和xpath都提取不出来想要的东西,要么就 ...
- scrapy下载中间件结合selenium抓取全国空气质量检测数据
1.所需知识补充 1.下载中间件常用函数 process_request(self, request, spider): 当每个request通过下载中间件是,该方法被调用 process_reque ...
- 用python+selenium抓取知乎今日最热和本月最热的前三个问题及每个问题的首个回答并保存至html文件
抓取知乎今日最热和本月最热的前三个问题及每个问题的首个回答,保存至html文件,该html文件的文件名应该是20160228_zhihu_today_hot.html,也就是日期+zhihu_toda ...
- 用python+selenium抓取微博24小时热门话题的前15个并保存到txt中
抓取微博24小时热门话题的前15个,抓取的内容请保存至txt文件中,需要抓取排行.话题和阅读数 #coding=utf-8 from selenium import webdriver import ...
随机推荐
- axio安装及使用
先安装 npm install axios --save 再导入 import $ from "jquery"; import axios from "axios&quo ...
- 设计模式C++描述----11.组合(Composite)模式
一. 举例 这个例子是书上的,假设有一个公司的组结结构如下: 它的结构很像一棵树,其中人力资源部和财务部是没有子结点的,具体公司才有子结点. 而且最关健的是,它的每一层结构很相似. 代码实现如下: / ...
- 【排列组合】给定一个M*N的格子或棋盘,从左下角走到右上角的走法总数(每次只能向右或向上移动一个方格边长的距离)
版权声明:本文为CSDN博主「梵解君」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明. 原文链接:https://blog.csdn.net/hadeso/art ...
- bit(比特)与Byte(字节)的区别与关系
1.bit:位 (小写b) 也称比特 是英文 binary digit的缩写 二进制数系统中,每个0或1就是一个位(bit)位是数据存储(计算机中信息)的最小单位计算机中的CPU位数指的是CPU一次能 ...
- VSCode实现文献管理
1 常用文献管理软件 常用的文献管理软件有mendely,zotero,endnote和Papers(需要付费),具体对比参考链接1.1.1.2 笔者只用过Mendely,当时综合考虑挑了Endnot ...
- winform 数据库资料导出Excel方法(适用于资料数据较多加载慢,不用呈现至DatagridView)
Private Sub savefile(ByVal dgv2 As DataTable) Dim app As Object = CreateObject("Excel.Applicati ...
- Feeling after reading《Jane Eyre》
Yesterday I read and listened over the book named <Jane Eyre>, the book is very thoughtful, th ...
- python学习之【第八篇】:Python中的函数基础
1.前言 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段.函数能提高应用的模块性,和代码的重复利用率. 2.函数的定义 定义函数时需要遵守以下规则: 函数代码块以 def 关键词开头 ...
- git上传项目到github远程库
最近在学习使用 git 上传管理项目,依照教程,建好了一个远程库,也实现了本地库与远程库的项目同步上传,但是在试着将本地库里的项目上传到另一个新建远程库时遇到了问题,一直上传不成功,经过一番查找摸索终 ...
- lrd 模拟 总结
觉得是时候总结一下达哥的考试了!达哥的考试我就没有考好过,就之前达哥的考试都是人家ak我爆零,然后这次也不例外,我总是想在考场上尝试一些新的东西,其实就是作死行为,有的时候这种行为可以为我带来收益但是 ...