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 ...
随机推荐
- unity 内置shader
几个有用的Unity 内置shader: (一)Standard RenderingMode:Opaque为实体渲染,更改Color的透明通道不会有影响:Cutout会把图片的透明通道显示出来,非严格 ...
- 源码学习系列之SpringBoot自动配置(篇一)
源码学习系列之SpringBoot自动配置源码学习(篇一) ok,本博客尝试跟一下Springboot的自动配置源码,做一下笔记记录,自动配置是Springboot的一个很关键的特性,也容易被忽略的属 ...
- js循环和调用
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- sql 经典查询50题 思路(一)
因为需要提高一下sql的查询能力,当然最快的方式就是做一些实际的题目了.选择了这个sql的50题,这次大概做了前10题左右,把思路放上来,也是一个总结. 具体题目见: https://zhuanlan ...
- SpringCloud之Hystrix服务降级(七)
Hystrix设计原则 1.防止单个服务的故障,耗尽整个系统服务的容器(比如tomcat)的线程资源,避免分布式环境里大量级联失败.通过第三方客户端访问(通常是通过网络)依赖服务出现失败.拒绝.超时或 ...
- 【MySQL】MySQL 8.0.X的安装与卸载命令
1.请读者自行下载MySQL Server https://dev.mysql.com/downloads/mysql/ 2.解压.zip文件 将mysql-8.0.12-winx64.zip解压到 ...
- [UWP]使用PointLight并实现动画效果
1. Composition Lighting UWP中的Composition Light是一组可以创建3D光照的API,它明明十分好玩而且强大, 但博客园几乎没有相关文章(用UWP或pointli ...
- Pandas 分组聚合
# 导入相关库 import numpy as np import pandas as pd 创建数据 index = pd.Index(data=["Tom", "Bo ...
- 如何在 Spring/Spring Boot 中做参数校验?你需要了解的都在这里!
本文为作者原创,如需转载请在文首著名地址,公众号转载请申请开白. springboot-guide : 适合新手入门以及有经验的开发人员查阅的 Spring Boot 教程(业余时间维护中,欢迎一起维 ...
- 『题解』洛谷P2357 守墓人
Portal Portal1: Luogu Description 在一个荒凉的墓地上有一个令人尊敬的守墓人,他看守的墓地从来没有被盗过, 所以人们很放心的把自己的先人的墓安顿在他那守墓人能看好这片墓 ...