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 ...
随机推荐
- IndentationError: unindent does not match any outer indentation level笔记
执行一个Python脚本的时候,报"IndentationError: unindent does not match any outer indentation level" 错 ...
- Cookie、Session、Token那点事儿
1.什么是Cookie? Cookie 技术产生源于 HTTP 协议在互联网上的急速发展.随着互联网时代的策马奔腾,带宽等限制不存在了,人们需要更复杂的互联网交互活动,就必须同服务器保持活动状态(简称 ...
- 洛谷P5522 【[yLOI2019] 棠梨煎雪】
区间操作考虑用线段树维护. 建\(n*2\)棵线段树,前\(n\)棵线段树维护每个串的第i位是否是0. 后\(n\)棵线段树维护每个串的第i位是否是1. 如果是问号的话,直接跳过就好(通过1和0能看出 ...
- 模板(ac):启发式合并
首先说明一点:线段树合并不是启发式合并. 启发式合并的大概内容就是:把小的数据结构按照这个数据结构的正常插入方法,一个一个地暴力塞进去. 而线段树合并显然不是这个东西. 这道题的题解太烂了,所以耽误了 ...
- NOIP模拟 25
分层考试第一场. 垫底. T1 lighthouse 观察到m很小,想到容斥. 正常人都想枚举子集,只有我打了搜索. 为了压行,我压缩了几句分类讨论. 压错了,原地爆炸 考场思路: 不容斥这也不可做啊 ...
- 简述同步和异步,以及js的任务队列.
javascript是单线程的一门语言,所以在执行任务的时候,所有任务必须排队,然后一个一个的执行.这就是同步模式 所以同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个 ...
- [LLL邀请赛]参观路线(图论+dfs)
emmmm....学校的oj被查水表了,扒不到原题面,所以.... 但是我还是扒到了题面... 题目大意:给定一个完全图,删掉其中一些边,然后求其字典序最小的遍历顺序 有点像去年day2T1啊.... ...
- Docker常见报错解决方法记录
[问题一]OCI runtime exec failed......executable file not found in $PATH": unknown [root@localhost ...
- php nginx反向代理获取真实ip的教程
php nginx反向代理获取真实ip的教程 <pre> location /getip { proxy_pass http://newmiracle.cn/ip.php; } proxy ...
- H5+app -- 自动更新
一.最近做了一个app自动更新功能,用的基本都是网上找得到的. 1.h5+ 规范 : http://www.html5plus.org/doc/zh_cn/maps.html 2.环形进度条插件:h ...