Python+Selenium爬取动态加载页面(2)
注: 上一篇《Python+Selenium爬取动态加载页面(1)》讲了基本地如何获取动态页面的数据,这里再讲一个稍微复杂一点的数据获取全国水雨情网。数据的获取过程跟人手动获取过程类似,所以也不会对服务器造成更大负荷。本文的代码见Selenium获取动态页面数据2.ipynb或Selenium获取动态页面数据2.py。同样在开始前需要准备环境,具体环境准备参考上一篇。
1、数据获取目标#
全国水雨情网的数据同样是动态加载出来的,在浏览中打开网页后http://xxfb.hydroinfo.gov.cn/ssIndex.html,可以看到回下图1-1所示的页面。
可以看到,其中并没有显示任何的数据,如果我们需要查看数据,还需要点击一下其中的几个按钮。比如,我们需要得到其中大型水库的数据,那么需要点击大型水库
按钮,得到如下图1-2所示的结果。
得到这个页面后,就可以从其中的HTML页面源码中解析数据了。
2、详细爬取过程#
2.1 打开网页#
运行下面代码,会自动弹出Chrome浏览器的窗口;如果用的browser = webdriver.PhantomJS()
,则没有窗口出来。浏览器的窗口出来后,可以看到,它加载出我们的页面了。
import re import pandas as pd from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC # 打开chrome浏览器(需提前安装好chromedriver) browser = webdriver.Chrome() # browser = webdriver.PhantomJS() # 这里经常出现加载超的异常,后面需要处理一下:捕获异常后,刷新浏览器 browser.get("http://xxfb.hydroinfo.gov.cn/ssIndex.html")
2.2 查找目标数据#
页面加载完成后,接下需要定位我们的大型水库
按钮,通过按浏览器的F12
查看源码,可以得到这个按钮的xpath://*[@id="sscontent"]/table/tbody/tr/td/table/tbody/tr[1]/td/table/tbody/tr/td[3]/a,如图2-1所示。
定位到按钮后,需要再点击一下。
# 找到大型水库的按钮---通过xpath btn_water_xpath = "//*[@id=\"sscontent\"]/table/tbody/tr/td/table/tbody/tr[1]/td/table/tbody/tr/td[3]/a" # 等待响应完成 wait = WebDriverWait(browser, 10) wait.until(EC.presence_of_element_located((By.XPATH, btn_water_xpath))) # 查找目标按钮 btn_water = browser.find_element_by_xpath(btn_water_xpath) # 找到按钮后单击 btn_water.click()
2.2 得到页面源码#
数据定位完成后,接下来得到页面源码。按照上面同样的方法,我们需要定位其中的数据表,并等待其加载完成,加载完成后,我们才能读取其页面源码。
# 大型水库的数据表--xpath water_table_xpath = "//*[@id=\"sktable\"]/table/tbody" # 得到新的页面,并等待其数据表加载完成 wait = WebDriverWait(browser, 10) wait.until(EC.presence_of_element_located( (By.XPATH, water_table_xpath))) soup = BeautifulSoup(browser.page_source, 'lxml')
2.3 提取数据#
得到页面源码后,可直接利用Pandas的read_html
方法得以其中的表格数据,非常方便。同时我们还需要定位它的表头信息,来得到我们的表头。
# 表头信息 table_head_csel = "#skcontent>table:nth-child(3)>tbody>tr" table_head = soup.select(table_head_csel)[0] # 通过css选择器,找到水库表信息 table_css_select = "#sktable" table_content = soup.select(table_css_select)[0] df_table = pd.read_html(str(table_content))[0] df_table.columns = [h.text for h in table_head.find_all("td")] # df_table.columns = ['流域', '行政区', '河名', '库名', '库水位(米)', \ # '蓄水量(亿米3)', '入库(米3/秒)', '堤顶高程(米)']
查看提取数据的前5行,如表2.1所示。
流域 | 行政区 | 河名 | 库名 | 库水位(米) | 蓄水量(亿米3) | 入库(米3/秒) | 堤顶高程(米) | |
---|---|---|---|---|---|---|---|---|
0 | 其他流域 | 新疆 | 乌伦古河 | 福海水库 | 575.14 ↓ | 1.756 | 0 | 579.00 |
1 | 其他流域 | 新疆 | 卡浪古尔河 | 喀浪古尔水库 | 988.26 — | 0.126 | 1.23 | 1007.50 |
2 | 其他流域 | 新疆 | 三屯河 | 三屯河水库 | 1024.49 — | 0.078 | 1.982 | 1039.60 |
3 | 其他流域 | 新疆 | 头屯河 | 头屯河水库 | 986.52 — | 0.108 | 1.75 | 995.20 |
4 | 其他流域 | 新疆 | 乌鲁木齐河 | 红雁池水库 | 995.54 ↓ | 0.234 | 0 | 1009.00 |
2.4 保存数据#
数据提取完成后,下面还将其表格的时间提取出来,以作为文件名,防止数据重复。这里利用了一个简单的正则表达式提时间信息,然后利用pandas的to_csv
方法,得到两种编码格式的.csv
文件。其中rvr_tab_2019_1_22_ch.csv
为中文编码格式,可直接用excel打开,如图2-2所示。
# 找到水库信息的时间 table_time_csel = "#skdate" time_text = soup.select(table_time_csel)[0].text time_info = re.search(r"(\d{4})年(\d{1,2})月(\d{1,2})", time_text).groups() df_table.to_csv("rvr_tab_%s_%s_%s.csv" % time_info, index=None) # 换一个编码方式,此文件可以直接用excel打开,不会出现乱码 df_table.to_csv("rvr_tab_%s_%s_%s_ch.csv" % time_info,encoding="GB18030", index=None)
总结#
本文的方法与上一篇《Python+Selenium爬取动态加载页面(1)》的方法类似,只是多一个按钮点击的过程。
从这两篇博文的数据提取过程来看,简单地,其数据获取有如下图所示的过程。
【推荐】100%开源!大型工业跨平台软件C++源码提供,建模,组态!
【推荐】AI 的力量,开发者的翅膀:欢迎使用 AI 原生开发工具 TRAE
【推荐】2025 HarmonyOS 鸿蒙创新赛正式启动,百万大奖等你挑战
· WPF 引用 ASP.NET Core 的 AOT 版本
· 通过 Canvas 将后端发来的一帧帧图片渲染成“视频”的实现过程
· 当加密ID需要变成Guid:为什么我选择了AES-CBC而非GCM?
· 基于 epoll 的协程调度器——零基础深入浅出 C++20 协程
· 下划线字段在golang结构体中的应用
· 我的AI自学路线,可能对你有用
· WPF 引用 ASP.NET Core 的 AOT 版本
· 纯 C#实现+AOT 打造的智能PDF目录提取工具 PdfTocExtractor
· C# 13 与 .NET 9 跨平台开发实战(第一章:开发环境搭建与.NET概述-下篇)
· 深入理解 C# 异步编程:同步、Task.Wait () 与 await 的本质区别及实践指南