Scrapy爬虫框架案例学习之六(爬取空气质量网历史数据需js解密)

1、网站分析

该网站搞了很多反爬技术,非常麻烦,最好是能通过Ajax请求获得数据,再进行解密,这样速度最快,但是技术要求较高。我这里还是用selenium中间件实现数据获取。后续再研究js解密。PM2.5历史数据_空气质量指数历史数据_中国空气质量在线监测分析平台历史数据

这个页面是个静态的页面,直接就能获取到所有的链接,然后我们找一个城市来进行详情数据的获取,比如朝阳,这个地方可以使用切片。

        url_list = response.xpath('//div[@class="bottom"]/ul/div[2]/li/a/@href').extract()
        print(url_list)
    #遍历列表
        for url in url_list[45:46]:
            city_url = response.urljoin(url)#发起对城市详情页面的请求
            #print(city_url)
            yield scrapy.Request(city_url,callback=self.parse_month)

详情页先是所有月度空气质量数据,通过详情页再获取到某月所有日的空气质量数据,我们要获得所有日的数据,需要再次发数据请求。

(1)获得所有月的空气质量数据页面的链接

这个网站做了限制,没有办法使用使用F12进行调试

 这个具体的原因就不详细介绍了,网站使用了无限 debugger,通过函数txsdefwsw()实现,如何能绕过这个方法太复杂,网上有教程,有兴趣的可以找下。

我通过view-source:https://www.aqistudy.cn/historydata/monthdata.php?city=%E6%9C%9D%E9%98%B3,就是view-source:可以查看到网页的源码,不影响做XPath解析。往后多拉一下就能看到。

 url_list = response.xpath('//ul[@class="unstyled1"]/li/a/@href').extract()
        #print(url_list)
        #遍历url列表中的部分
        for url in url_list[50:51]:
            month_url =response.urljoin(url)#发起详情页面请求

 (2)获取某个月的详情数据,需要再次请求,这时遇到一个问题就是打开的页面加载是动态的,比较慢,通过view-source看不到具体的数据,这只能通过selenium中间件技术来获取页面的源码,page_source,这个页面的源码通过print是可以看到数据的。因此中间件就是将请求截取,通过再次包装,提交请求。if 'daydata' in url:凡是页面链接URL中含有daydata的就通过selenium发出请求获取数据。

2、代码详情

middlewares.py

# Define here the models for your spider middleware
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/spider-middleware.html

from scrapy import signals
from itemadapter import is_item, ItemAdapter
import time
from selenium import webdriver
from scrapy.http import HtmlResponse

class SelenimuMiddleWare(object):
    def process_request(self,request,spider):
        url =request.url
        print(url)
        if 'daydata' in url:

            options = webdriver.ChromeOptions()
            options.add_experimental_option('useAutomationExtension', False)
            options.add_experimental_option('excludeSwitches', ['enable-automation'])
            #options.add_argument('--headless')#无头浏览器
            #options.add_argument('--disable-gpu')

            driver = webdriver.Chrome(options=options)
            driver.execute_cdp_cmd(
                "Page.addScriptToEvaluateOnNewDocument",
                {"source":"""
                Object.defineProperty(navigator,'webdriver',{
                  get: () => undefined
                })
              """})

            driver.get(url)
            time.sleep(5)
            data = driver.page_source
            print(data)
            driver.close()
            res = HtmlResponse(url=url,body = data,encoding='utf-8',request = request)
            return res

爬虫文件aqi

import scrapy
from AQI.items import AqiItem
import time

class AqiSpider(scrapy.Spider):
    name = "aqi"
    allowed_domains = ["aqistudy.cn"]
    host = "https://www.aqiStudy.cn/historydata/"
    start_urls = [host]

    #解析起始url对应的响应
    def parse(self,response):
    #获取城市url列表
        url_list = response.xpath('//div[@class="bottom"]/ul/div[2]/li/a/@href').extract()
        print(url_list)
    #遍历列表
        for url in url_list[45:46]:
            city_url = response.urljoin(url)#发起对城市详情页面的请求
            #print(city_url)
            yield scrapy.Request(city_url,callback=self.parse_month)


    #解析详情页面请求对应的响应
    def parse_month(self, response):
    #获取每月详情url列表
        #print(response.text)
        url_list = response.xpath('//ul[@class="unstyled1"]/li/a/@href').extract()
        #print(url_list)
        #遍历url列表中的部分
        for url in url_list[50:51]:
            month_url =response.urljoin(url)#发起详情页面请求
            print(month_url)
            yield scrapy.Request(month_url,callback=self.parse_day)

    def parse_day(self, response):
        #print(response.url)
        #获取所有的数据节点
        node_list = response.xpath('//tr')
        node_list.pop(0)
        city = response.xpath('//div[@class="panel-heading"]/h3/text()').extract_first().split('2')[0]
        #遍历数据节点列表
        item = AqiItem()
        for node in node_list:
        #创建存储数据的item容器item = AqiItem()
        #先填写一些固定参数
            item['city'] = city
            item['url'] = response.url
            item['timestamp']= time.time()
            item['date'] = node.xpath('./td[1]/text()').extract_first()
            item['AQI'] = node.xpath('./td[2]/text()').extract_first()
            item['level'] = node.xpath('./td[5]/span/text()').extract_first()
            # item['pm2_5'] = node.xpath('./td[4]/text()').extract_first()
            # item['pm10'] = node.xpath('./td[5]/text()').extract_first()
            # item['pm2_5'] = node.xpath('./td[4]/text()').extract_first()
            # item['pm10'] = node.xpath('./td[5]/text()').extract_first()
            # item['so2'] = node.xpath('./td[6]/text()').extract_first()
            # item['co'] = node.xpath('./td[7]/text()').extract_first()
            # item['no2'] = node.xpath('./td[8]/text()').extract_first()
            # item['o3'] = node.xpath('./td[9]/text()').extract_first()

            yield item

        

 3、问题

拿到的渲染后的网页源代码,其中包含了3个 table,每个 Table 都有数据,但只有1个table 的数据是真实的,其他2个都是 js 代码造的假数据。就算拿到了这个真实的 table,单元格 td 里面也有伪造的假数据,css 设置了隐藏(hidden 或者 display none),需要把这些假数据剔除掉。

真实页面显示的数据

通过driver.page_source获得的源码,保存到html文件,用浏览器打开。 

数据也对不上,应该是通过加密了。页面最下面有2个密文。

这个需要破解后才能看到是什么,有兴趣的小伙伴可以百度下。如果能拿到加密解密的js函数,可以通过import execjs这个模块,在python里面执行JS函数,获得解密后的数据,那么应该就不会出现数据混乱的问题了。如果系统的学习后,再交流,如有不正确的地方,欢迎批评指正。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
爬取空气质量检测的部分城市的历年每天质量数据 思路----------------------------------------- 从某城市的空气质量页获取某市每月的链接,再爬取每个月的表格数据。连云港市:https://www.aqistudy.cn/historydata/daydata.php?city=连云港 连云港2014年5月的空气质量:https://www.aqistudy.cn/historydata/daydata.php?city=连云港&month=2014-05 遇到的问题----------------------------------------- 获取的页中的表格数据隐藏,尝试requests无法获取。判断可能是动态加载的页 尝试----------------------------------------- 1. 通过XHR,js查找隐藏数据的加载页,没有找到。 2. 使用phantomjs.get() result=pd.read_html ,可以获得隐藏的表格数据,但是并不稳定,只是偶尔出现加载的表格数据,无法大规模的获取 解决方法----------------------------------------- 查找资料得知这个站的表格数据在Console里的items中, 使用selenium的webdriver.firefox(),driver.execute_script("return items") 数据可获得。 仍遇到的问题:----------------------------------------- 爬取一个页可获得数据,但是连续的获取页,会出现两个错误。 1.Message: ReferenceError: items is not defined 2.connection refused 解决方法: 1.connection refused问题,可能是页开太多,使用driver.quit() 2. 如果 execute_script 还是出错,可尝试pd.read_html获取信息。之前用phantomjs获取的时候输出空的表格,可能由于加载不够,用 Waite直到table出现之后再获取页 Element=wait.until(EC.element_to_be_clickable((By.XPATH,"/html/body/div[3]/div[1]/div[1]/table/tbody"))) 3.之后出现偶尔出现输出为空,使用循环,如果输出表格为空,再重新获取。 if len(result)>1: filename = str(month) + '.xls' result.to_excel('E:\python\案例程序\data\\' + filename) print('成功存入'+filename) driver.quit() else: driver.quit() return getdata(monthhref,month)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值