爬取某城市各监测站点历史每日空气质量数据

声明原代码出处(威斯登):python爬取某城市各监测站点历史空气质量数据_爬取空气质量数据_威斯登的博客-CSDN博客

数据分析需要所以爬数据,在这边找了好几个代码,有的不是自己需要的且没跑通。由于Python更新过,所以本篇内容在威斯登代码基础上做了一点修改,已经运行成功。

使用软件版本:Pythonv3.11,Firefoxv113.0.1。之前用过Google,但是总被挡住所以放弃。

代码使用时注意输入日期不必输入完整的8位年-月-日,比如2022年5月1日不用输入“2022-05-01”,会出错。直接输入“2022-5-1”即可。

谢谢在此分享的各位。

import csv
import time
import unittest
import numpy as np
import pandas as pd
import openpyxl as op
from selenium import webdriver
from selenium.webdriver.common.by import By

# 火狐浏览器selenium方式
driver = webdriver.Firefox()

# 时间选择函数,定位到指定的时间
def TimeSelect(driver, star_data):
    # 激活时间控件下拉框
    driver.find_element(By.CSS_SELECTOR, "input#reservation2").click()
    time.sleep(1)
    data_conver = {'一': '1', '二': '2', '三': '3', '四': '4', '五': '5', '六': '6', '七': '7', '八': '8', '九': '9',
                   '十': '10', '十一': '11', '十二': '12'}
    # print("请输入日期(例如:2022-11-20)")
    inyear, inmonth, inday = star_data.split("-")
    # print(b)
    t = 0  # 控件向前向后点,class不一样,用来判断
    # ---------------操作左边的控件---------------------
    data_original = driver.find_element(By.XPATH,  # 获得左边控件原始日期
        "//div[@class='calendar left']//div//tr//th[@class='month']").get_attribute("textContent")
    a, b = data_original.split(" ")  # 按空格拆分出年和月
    data_or_year = b  # 原始日期年
    data_or_month = data_conver[a[0:a.rfind('月', 1)]]  # 原始日期月
    data_or_day = int(driver.find_element(By.XPATH,  # 初始日期日
        "//div[@class='calendar left']//div//tbody//td[@class='available'][1]").get_attribute("textContent"))

    while 1:  # 定位到所输入的时间,年和月
        if (int(data_or_year) > int(inyear)):  # 定位所输入的年份
            driver.find_element(By.XPATH,  # 点击左边的箭头控件
                "//div[@class='calendar left']//div//table//th[@class='prev available']//i").click()
            data_original = driver.find_element(By.XPATH,  # 获得左边控件日期
                "//div[@class='calendar left']//div//tr//th[@class='month']").get_attribute("textContent")
            a, b = data_original.split(" ")  # 按空格拆分出年和月
            data_or_year = b  # 原始日期年
            data_or_month = data_conver[a[0:a.rfind('月', 1)]]  # 原始日期月

        elif (int(data_or_month) > int(inmonth)):  # 定位所输入的月份
            driver.find_element(By.XPATH,  # 点击左边的控件
                "//div[@class='calendar left']//div//table//th[@class='prev available']//i").click()
            data_original = driver.find_element(By.XPATH,  # 获得左边控件日期
                "//div[@class='calendar left']//div//tr//th[@class='month']").get_attribute("textContent")
            a, b = data_original.split(" ")  # 按空格拆分出年和月
            data_or_year = b  # 原始日期年
            data_or_month = data_conver[a[0:a.rfind('月', 1)]]  # 原始日期月
            print(data_original)

        elif (int(data_or_year) < int(inyear)):
            driver.find_element(By.XPATH,  # 点击右边的箭头控件
                "//div[@class='calendar left']//div//table//th[@class='next available']//i").click()
            data_original = driver.find_element(By.XPATH,  # 获得左边控件日期
                "//div[@class='calendar left']//div//tr//th[@class='month']").get_attribute("textContent")
            a, b = data_original.split(" ")  # 按空格拆分出年和月
            data_or_year = b  # 原始日期年
            data_or_month = data_conver[a[0:a.rfind('月', 1)]]  # 原始日期月
            print(data_original)
            t = 1

        elif (int(data_or_month) < int(inmonth)):
            driver.find_element(By.XPATH,  # 点击右边的箭头控件
                "//div[@class='calendar left']//div//table//th[@class='next available']//i").click()
            data_original = driver.find_element(By.XPATH,  # 获得左边控件日期
                "//div[@class='calendar left']//div//tr//th[@class='month']").get_attribute("textContent")
            print(data_original)
            a, b = data_original.split(" ")  # 按空格拆分出年和月
            data_or_year = b  # 原始日期年
            data_or_month = data_conver[a[0:a.rfind('月', 1)]]  # 原始日期月
            t = 1
        elif (data_or_year == inyear and data_or_month == inmonth):
            break
        print(inyear, inmonth)
        print(data_or_year, data_or_month)
    # 定位到该月的具体天
    day_list_left = driver.find_element(By.XPATH,
        "//div[@class='calendar left']//div//tbody//tr//td[@class='available']").click()  # 日期日
    #d = int(inday)
    #day_list_left[d - 1].click()  # 点击该天

    # ---------------操作右边的控件---------------------
    data_original = driver.find_element(By.XPATH,  # 获得右边控件原始日期
        "//div[@class='calendar right']//div//tr//th[@class='month']").get_attribute("textContent")
    a, b = data_original.split(" ")  # 按空格拆分出年和月
    data_or_year = b  # 原始日期年
    data_or_month = data_conver[a[0:a.rfind('月', 1)]]  # 原始日期月

    while 1:  # 定位到所输入的时间,年和月
        if (data_or_year != inyear):  # 定位所输入的年份
            driver.find_element(By.XPATH,  # 点击左边的箭头控件
                "//div[@class='calendar right']//div//table//th[@class='prev available']//i").click()
            data_original = driver.find_element(By.XPATH,  # 获得左边控件日期
                "//div[@class='calendar right']//div//tr//th[@class='month']").get_attribute("textContent")
            a, b = data_original.split(" ")  # 按空格拆分出年和月
            data_or_year = b  # 原始日期年
            data_or_month = data_conver[a[0:a.rfind('月', 1)]]  # 原始日期月

        elif (data_or_month != inmonth):  # 定位所输入的月份
            driver.find_element(By.XPATH,  # 点击左边的控件
                "//div[@class='calendar right']//div//table//th[@class='prev available']//i").click()
            data_original = driver.find_element(By.XPATH,  # 获得左边控件日期
                "//div[@class='calendar right']//div//tr//th[@class='month']").get_attribute("textContent")
            a, b = data_original.split(" ")  # 按空格拆分出年和月
            data_or_year = b  # 原始日期年
            data_or_month = data_conver[a[0:a.rfind('月', 1)]]  # 原始日期月
        else:
            break
    if (t == 0):
        # 定位到该月的具体天
        day_list_right = driver.find_element(By.XPATH,
            "//div[@class='calendar right']//div//tbody//tr//td[@class='available in-range']").click()  # 日期日
        #day_list_right[0].click()  # 点击该天

    driver.find_element(By.XPATH,  # 时间选择好了,点击确定按钮
        "//div[@class='range_inputs']//button[1]").click()

    return star_data


def BackData(driver, end_data, in_day, mid_end_day):
    data_conver = {'一': '1', '二': '2', '三': '3', '四': '4', '五': '5', '六': '6', '七': '7', '八': '8', '九': '9',
                   '十': '10', '十一': '11', '十二': '12'}

    end_year, end_month, end_day = end_data.split("-")
    d = int(in_day) - 1  # star_day-1

    while 1:
        print(d)
        if (str(d + 2) == mid_end_day):
            break
        else:
            # 激活时间控件下拉框
            driver.find_element(By.CSS_SELECTOR, "input#reservation2").click()
            time.sleep(1)
            # ---------------操作左边的控件---------------------
            data_original = driver.find_element(By.XPATH,  # 获得左边控件原始日期
                "//div[@class='calendar left']//div//tr//th[@class='month']").get_attribute("textContent")
            a, b = data_original.split(" ")  # 按空格拆分出年和月
            data_or_year = b  # 原始日期年
            data_or_month = data_conver[a[0:a.rfind('月', 1)]]  # 原始日期月

            # 定位到该月的具体天
            day_list_left = driver.find_elements(By.XPATH,
                "//div[@class='calendar left']//div//tbody//tr//td[@class='available']")  # 日期日
            day_list_left[d].click()  # 点击该天
            # day_list_left[d].get_attribute("textContent")

            driver.find_element(By.XPATH,  # 时间选择好了,点击确定按钮
                "//div[@class='range_inputs']//button[1]").click()

            left_data = str(data_or_year) + '-' + data_or_month + '-' + str(d + 2)
            print(left_data)
            DataRead(driver, left_data)
            d = d + 1

    return 0


# 读取指定时间的空气质量数据
def DataRead(driver, left_data):
    time.sleep(3)
    text_list1 = driver.find_elements(By.XPATH,
        "//div[@id='pointchart']//*[@class='highcharts-axis-labels highcharts-xaxis-labels']//*")
    text_list2 = driver.find_elements(By.XPATH,
        "//div[@id='pointchart']//*[@class='highcharts-data-labels highcharts-tracker']//*")

    print(text_list1)
    print(text_list2)

    button_point = ["button[value='PM2.5']", "button[value='PM10']", "button[value='SO2']",
                    "button[value='NO2']", "button[value='CO']", "button[value='O3']"]
    Jpoints = ["PM2.5", "PM10", "SO2", "NO2", "CO", "O3"]

    dict = {}

    # 第一个AQI写入文件
    for i, j in zip(range(len(text_list1)),
                    range(0, len(text_list2), 2)):  # 值不知道为什么有两个重复,所以步长设为2,跳过一个取值,这样取出来的值才没有重复
        str1 = text_list1[i].get_attribute('textContent')
        str2 = text_list2[j].get_attribute('textContent')
        # print(str1)
        # print(str2)
        dict[str1] = str2  # 按字典方式存放
    # print(dict)  # 原始字典

    d_order = sorted(dict.items(), key=lambda x: x[0], reverse=False)  # 按字典集合中,每一个元组的第二个元素排列,最后结果是一个列表
    # print(d_order)  #按照监测点排序后的列表

    c_order = {}
    for n in range(len(text_list1)):  # 将排序后的列表转换成字典,方便写入表格
        c_order[d_order[n][0]] = d_order[n][1]
    print(c_order)

    # 提取字典中的两列值key是键值,value是cont【key】对应的值
    key = list(c_order.keys())
    value = list(c_order.values())
    # print(key)
    # print(value)

    # 利用pandas模块先建立DateFrame类型,然后将两个上面的list存进去
    result_excel = pd.DataFrame()
    result_excel["监测点"] = key
    result_excel["AQI"] = value
    # 写入excel

    result_excel.to_excel(left_data + "监测点.xlsx")

    # 后六个写入文件
    m = 4
    for k in range(6):
        dict = {}
        c_order = {}
        d_order = []
        value2 = []
        key2 = []
        driver.find_elements(By.CSS_SELECTOR, button_point[k])[2].click()
        text_list1 = driver.find_elements(By.XPATH,
            "//div[@id='pointchart']//*[@class='highcharts-axis-labels highcharts-xaxis-labels']//*")
        text_list2 = driver.find_elements(By.XPATH,
            "//div[@id='pointchart']//*[@class='highcharts-data-labels highcharts-tracker']//*")

        for j, c in zip(range(len(text_list1)), range(0, len(text_list2), 2)):
            str1 = text_list1[j].get_attribute('textContent')
            str2 = text_list2[c].get_attribute('textContent')
            dict[str1] = str2
            # print(str1)
            # print(str2)
        # print(dict)
        d_order = sorted(dict.items(), key=lambda x: x[0], reverse=False)  # 按字典集合中,每一个元组的第二个元素排列
        # print(d_order)

        for p in range(len(text_list1)):
            c_order[d_order[p][0]] = d_order[p][1]
        print(c_order)

        # 提取字典中的两列值key是键值,value是c_order【key】对应的值
        key2 = list(c_order.keys())
        value2 = list(c_order.values())
        # print(value2)

        bg = op.load_workbook(left_data + "监测点.xlsx")  # 应先将excel文件放入到工作目录下
        sheet = bg["Sheet1"]  # “Sheet1”表示将数据写入到excel文件的sheet1下
        sheet.cell(1, m, Jpoints[k])
        for i in range(1, len(value2) + 1):
            sheet.cell(i + 1, m, value2[i - 1])  # sheet.cell(1,1,num_list[0])表示将num_list列表的第0个数据1写入到excel表格的第一行第一列
        bg.save(left_data + "监测点.xlsx")  # 对文件进行保存
        m = m + 1
    driver.find_elements(By.CSS_SELECTOR, "button[value='AQI']")[1].click()  # 重新点击AQI按钮,这样下次读取的时候还是从AQI开始读取
    return 0


class seleniumTest(unittest.TestCase):
    def setUp(self):
        # 调试的时候用firefox比较直观
        self.driver = webdriver.Firefox()

    def testEle(self):
        driver = self.driver
        # 浏览器窗口最大化
        driver.maximize_window()
        # 浏览器地址定向为页面
        driver.get("https://www.zq12369.com/environment.php?tab=city&city=天津&order=DESC#envtab")

        # 让webdriver操纵当前页
        driver.switch_to.default_content()
        # 滚动条拉到指定位置(具体元素)
        target = driver.find_element(By.ID, "pointchart")
        driver.execute_script("arguments[0].scrollIntoView();", target)
        time.sleep(3)

        print("请输入起止日期(例如:2020-11-20)")
        start_data = input()
        print("请输入截至日期(例如:2021-11-20)")
        end_data = input()
        in_year, in_month, in_day = start_data.split("-")
        end_year, end_month, end_day = end_data.split("-")

        month_31 = ['1', '3', '5', '7', '8', '10', '12']
        month_30 = ['2', '4', '6', '9', '11']
        while 1:
            t = 0
            for i in range(len(month_31)):  # 该月31天设t=1
                if (month_31[i] == in_month):
                    t = 1
            for i in range(len(month_30)):  # 该月30天设t=2
                if (month_30[i] == in_month):
                    t = 2
            print("#######################################")
            print(in_year, in_month, in_day)
            print(end_year, end_month, end_day)
            print("#######################################")
            if (in_year == end_year and in_month == str(int(end_month) + 1)):
                break
            else:
                left_data = TimeSelect(driver, start_data)
                DataRead(driver, left_data)

                if (t == 1):
                    mid_end_day = "32"
                elif (t == 2):
                    mid_end_day = "31"
                else:
                    mid_end_day = "29"

                if (in_month == end_month):
                    mid_end_day = end_day

                mid_data = in_year + "-" + in_month + "-" + mid_end_day
                print('---------mid_data--------------')
                print(mid_data)
                print('---------mid_data--------------')
                BackData(driver, mid_data, in_day, mid_end_day)
                in_month = str(int(in_month) + 1)
                in_day = '1'
                start_data = in_year + '-' + in_month + '-' + in_day

        print('成功')

    def tearDown(self):
        self.driver.quit()


if __name__ == '__main__':
    unittest.main()

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值