声明原代码出处(威斯登):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()