Python Selenium爬虫实战:高效抓取政府网站政策文件构建语料库 1. 项目概述与核心价值最近在做一个数据分析项目需要收集近五年某个特定领域的政策文件作为语料库。手动去各个政府网站翻找效率低不说还容易遗漏。于是我决定用Python写一个爬虫来批量抓取。政府网站的结构通常比较规整但很多内容是通过JavaScript动态加载的简单的requests库配合BeautifulSoup解析静态HTML往往力不从心。这时候Selenium配合ChromeDriver模拟真实浏览器操作的优势就体现出来了。这个组合不仅能处理动态内容还能应对一些简单的反爬机制比如需要点击“加载更多”或者翻页的列表页。这个实战项目我将带你从零开始搭建一个能够稳定、高效抓取政府网站政策文件的爬虫。我们会涵盖环境配置、页面分析、Selenium自动化操作、数据提取与存储以及最重要的——如何遵守网络礼仪做一个“有道德”的爬虫。无论你是数据分析师、研究者还是对Python自动化感兴趣的学习者这套方案都能为你节省大量时间。我会附上完整的、可运行的代码并解释每一行关键代码背后的逻辑让你不仅能“抄作业”更能理解“为什么这么写”。2. 环境准备与工具选型解析2.1 为什么选择Selenium ChromeDriver在爬虫领域工具链的选择直接决定了项目的成败和复杂度。对于政府网站这类目标我选择SeleniumChromeDriver组合主要基于以下几点考量首先JavaScript渲染是首要障碍。现代网站包括许多政府门户大量使用Ajax、Vue、React等前端框架来动态加载内容。政策文件列表、分页按钮、详情弹窗等元素很可能在初始HTML中并不存在而是由JS脚本后续生成的。使用传统的requestsBeautifulSoup组合只能获取到初始的“空壳”HTML无法拿到我们需要的真实数据。Selenium的核心价值在于它通过驱动一个真实的浏览器如Chrome来访问网页等待所有JS执行完毕、页面完全渲染后再获取完整的DOM树从而完美解决动态内容问题。其次操作模拟能力至关重要。抓取流程往往不是简单的“访问一个URL解析HTML”。我们可能需要模拟点击“下一页”按钮、在搜索框输入关键词、点击“展开”或“加载更多”链接甚至处理一些简单的验证步骤如下拉选择年份、地区。Selenium提供了丰富的API来模拟这些真实的用户交互行为如点击(click())、输入(send_keys())、选择下拉框等使得爬虫能够像真人一样浏览网站完成复杂的多步骤数据采集任务。再者稳定性和兼容性。Chrome浏览器市场占有率极高政府网站在Chrome上的兼容性通常是最好的。使用ChromeDriver驱动官方Chrome浏览器能最大程度还原用户访问场景减少因浏览器差异导致的页面布局错乱或脚本执行失败问题。相比于一些无头浏览器方案带界面的Chrome在开发调试阶段也更直观你可以亲眼看到爬虫每一步在做什么便于排查问题。最后反爬虫策略的温和应对。虽然Selenium自动化特征明显但对于访问频率不高、目标为公开信息的政府网站其模拟真人操作的行为模式如随机等待、完整的浏览器指纹反而比一些高并发、特征明显的请求库更不容易触发严格的反爬机制。当然这绝不意味着可以肆意妄为我们依然要严格遵守robots.txt并控制访问频率。2.2 详细环境搭建步骤工欲善其事必先利其器。下面我们来一步步搭建开发环境。我推荐使用Python 3.8或更高版本以及Chrome浏览器。第一步安装Python及包管理工具pip确保你的系统已安装Python。打开命令行Windows的CMD/PowerShellMac/Linux的Terminal输入python --version检查。如果未安装请前往Python官网下载安装包安装时务必勾选“Add Python to PATH”。pip通常会随Python一同安装可用pip --version验证。第二步安装必要的Python库我们将主要用到selenium库。在命令行中执行以下命令进行安装pip install selenium这个命令会从PyPIPython包索引下载并安装最新稳定版的Selenium。第三步下载与Chrome浏览器版本匹配的ChromeDriver这是最关键也最容易出错的一步。ChromeDriver是一个独立的可执行文件Selenium通过它来控制和通信Chrome浏览器。必须保证ChromeDriver的主版本号与你电脑上已安装的Chrome浏览器的主版本号完全一致例如Chrome版本是 120.0.6099.110那么ChromeDriver也应下载120.x.x.x版本。查看Chrome版本打开Chrome浏览器点击右上角三个点 - 帮助 - 关于Google Chrome即可看到版本号记下主版本号如120。下载ChromeDriver官方途径访问ChromeDriver的官方下载站点。在网站列表中找到与你Chrome主版本号相同的版本进行下载。例如你的Chrome是120版就下载“ChromeDriver 120.0.6099.x”系列。选择正确文件根据你的操作系统下载对应的压缩包Windows选chromedriver_win32.zipMac Intel芯片选chromedriver_mac64.zipMac Apple芯片选chromedriver_mac_arm64.zipLinux选chromedriver_linux64.zip。配置ChromeDriver将下载的ZIP包解压你会得到一个名为chromedriverWindows下为chromedriver.exe的可执行文件。方法一推荐方便管理将此文件放置在一个你常用的目录下例如C:\WebDriver\或/usr/local/bin/。然后将这个目录的路径添加到系统的环境变量PATH中。这样你可以在任何位置通过命令行启动它。方法二项目内引用将chromedriver.exe文件直接放在你的Python项目根目录下。在代码中你需要指定它的完整路径来初始化。注意Chrome浏览器会自动更新而ChromeDriver不会。如果某天你的爬虫突然报错提示“This version of ChromeDriver only supports Chrome version xxx”十有八九是浏览器自动升级了。你需要重复第三步下载匹配新版本Chrome的ChromeDriver替换旧文件。第四步验证安装创建一个简单的Python脚本test_env.py来测试环境是否正常from selenium import webdriver from selenium.webdriver.chrome.service import Service # 如果你将chromedriver加入了PATH可以这样初始化 driver webdriver.Chrome() # 或者如果你将chromedriver放在项目目录需要指定路径 # service Service(executable_path./chromedriver.exe) # Windows # service Service(executable_path./chromedriver) # Mac/Linux # driver webdriver.Chrome(serviceservice) driver.get(http://www.baidu.com) print(driver.title) # 应该打印出“百度一下你就知道” driver.quit() # 关闭浏览器运行这个脚本如果成功弹出一个Chrome浏览器窗口并打开百度页面然后在控制台打印出标题后关闭说明环境配置成功。3. 目标网站分析与爬虫策略设计3.1 目标网站结构探查在开始写代码之前我们必须像侦察兵一样先摸清“敌情”。以某个典型的省级政府政策发布网站为例我们的目标是抓取“政策文件”栏目下的所有文件。打开网站按F12进入开发者工具这是我们爬虫工程师的“望远镜”和“显微镜”。首先分析列表页。通常政策文件会以列表形式呈现每页显示10-20条。我们需要观察URL规律翻页时URL是如何变化的是像?page2这样的查询参数还是像/page/2/这样的路径或者是通过JavaScript POST请求加载政府网站以前两种居多。列表元素定位在Elements面板找到每条政策记录的HTML结构。它通常包裹在一个div或li标签里里面包含标题a标签、文号、发布日期、发文机构等。我们需要找到能够唯一、稳定地定位到每条记录的CSS选择器或XPath。翻页机制找到“下一页”或页码按钮。查看它的HTML元素如a classnext或lia2/a/li并确认点击它是否能正确触发页面跳转或AJAX加载。其次分析详情页。点击一条政策标题进入文件详情页。我们需要观察文件标题通常在一个h1或h2标签内。元信息发文日期、文号、发文机构、主题分类等。这些信息可能在一个div classmeta里也可能分散在多个span中。文件正文这是核心内容。可能是直接以HTML段落p形式呈现也可能是嵌入了一个PDF阅读器或者直接提供了PDF文件的下载链接。附件很多政策文件会附带PDF、Word等格式的附件。我们需要找到附件区域的HTML元素和附件链接通常是a href...pdf。最后也是最重要的一步检查robots.txt。在浏览器地址栏输入https://目标网站域名/robots.txt。这个文件规定了网络爬虫哪些目录可以访问哪些不可以。例如你可能会看到User-agent: * Disallow: /search/ Disallow: /admin/ Allow: /public/这表示禁止所有爬虫访问/search/和/admin/目录但允许访问/public/。我们必须严格遵守robots.txt的约定只抓取Allow的或未被Disallow的公开目录。这是对网站运营者的基本尊重也是避免法律风险和技术封锁的底线。3.2 爬虫流程与代码结构设计基于以上分析我们可以设计出爬虫的核心工作流并规划代码模块。核心工作流初始化驱动启动Selenium配置浏览器选项如无头模式、禁用图片加载以加速。访问列表首页打开政策文件列表的第一页。解析当前列表页使用WebDriverWait等待列表内容加载完成。使用find_elements方法配合CSS选择器获取当前页所有政策条目的容器元素。遍历这些容器从每个容器中提取出政策标题、详情页链接、发布日期等基本信息。进入详情页并抓取对于每条政策点击标题或通过链接跳转到详情页。等待详情页关键内容如正文加载。提取详情页的完整信息标题、文号、正文、附件链接等。将数据存储到数据结构如字典中。退回列表页使用driver.back()或管理多个标签页。处理翻页判断是否存在“下一页”按钮。如果存在模拟点击然后回到第3步。如果不存在或到达指定页数结束循环。数据存储与清理将收集到的所有政策数据保存为文件如JSON、CSV。关闭浏览器驱动。代码模块设计 为了使代码清晰、易维护我们可以将其组织成几个函数或类init_driver(): 负责创建并配置WebDriver实例。parse_list_page(driver, url): 负责解析列表页返回当前页的政策条目信息列表每个条目包含标题、链接等。parse_detail_page(driver, detail_url): 负责解析详情页返回政策的完整信息字典。save_to_file(data, filename): 负责将数据保存到JSON或CSV文件。主函数main(): 串联整个流程控制翻页循环。这种模块化设计的好处是如果未来网站结构发生变化我们通常只需要修改parse_list_page和parse_detail_page这两个解析函数而不必动整个流程。4. Selenium核心操作与等待机制详解4.1 元素定位与交互操作Selenium提供了八种主要的元素定位方式最常用的是ID、Class Name、CSS Selector和XPath。对于政府网站这类结构规整但可能ID不唯一的页面CSS Selector通常是性能和可读性的最佳平衡点。定位元素from selenium.webdriver.common.by import By # 通过ID定位最快但ID可能动态生成或重复 element driver.find_element(By.ID, “searchInput”) # 通过CSS Class定位 elements driver.find_elements(By.CLASS_NAME, “policy-item”) # 返回列表 # 通过CSS选择器定位最灵活强大 # 定位class为‘policy-list’下的所有li标签 items driver.find_elements(By.CSS_SELECTOR, “.policy-list li”) # 定位包含特定文本的a标签 link driver.find_element(By.CSS_SELECTOR, “a:contains(‘下一页’)”) # 通过XPath定位功能强大但可能较慢且脆弱 # 定位文本为“关于印发...的通知”的任意元素 title driver.find_element(By.XPATH, “//*[text()‘关于印发...的通知’]”)实操心得优先使用find_elements复数形式它返回一个列表即使找不到元素也是空列表不会抛出异常使代码更健壮。使用Chrome开发者工具的“检查”功能右键点击元素选择“Copy - Copy selector”或“Copy - Copy XPath”可以快速获取定位表达式但需要人工校验其稳定性和唯一性。元素交互 定位到元素后就可以模拟用户操作了。# 输入文本如搜索框 search_box driver.find_element(By.ID, “keyword”) search_box.clear() # 先清空避免残留内容 search_box.send_keys(“科技创新政策”) # 点击元素 search_button driver.find_element(By.CSS_SELECTOR, “.search-btn”) search_button.click() # 获取元素属性、文本 link_url link.get_attribute(“href”) policy_title title.text # 执行JavaScript用于复杂操作或获取特殊属性 # 例如滚动到页面底部以触发懒加载 driver.execute_script(“window.scrollTo(0, document.body.scrollHeight);”) # 获取通过JS计算的样式 color driver.execute_script(“return window.getComputedStyle(arguments[0]).color;”, element)4.2 显式等待与隐式等待网络有延迟页面加载和JavaScript执行需要时间。如果代码在元素还没出现时就尝试去定位或操作它就会抛出NoSuchElementException异常。Selenium提供了两种等待机制。隐式等待 (Implicit Wait) 在创建WebDriver后设置一次对整个驱动生命周期有效。它告诉WebDriver在查找任何元素时如果元素没有立即出现就等待一段设定的时间如10秒期间会轮询查找一旦找到就继续执行。driver.implicitly_wait(10) # 单位秒它的缺点是不够灵活并且只对find_element这类查找操作有效对元素是否可点击、是否可见无效。显式等待 (Explicit Wait)这是更推荐、更精确的方式。它允许你为某个特定的条件设置等待直到条件成立才继续执行否则超时后抛出异常。这需要配合WebDriverWait和expected_conditionsEC模块使用。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 等待直到某个元素出现在DOM中并且可见 wait WebDriverWait(driver, 10) # 最长等待10秒 element wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, “.policy-list”))) # 等待直到某个元素可以被点击 next_button wait.until(EC.element_to_be_clickable((By.LINK_TEXT, “下一页”))) next_button.click() # 等待直到页面标题包含特定文字 wait.until(EC.title_contains(“政策文件”)) # 等待直到某个元素从DOM中消失如加载动画 wait.until(EC.invisibility_of_element_located((By.ID, “loading”)))注意事项在实际项目中我几乎总是使用显式等待。它代码意图更清晰能精确等待我们关心的特定状态避免不必要的全局等待提高爬虫效率。一个常见的模式是在关键操作如点击翻页、进入详情页后立即使用显式等待下一个关键元素出现这样代码既健壮又高效。5. 完整爬虫代码实现与逐行解析下面我将以一个模拟的政府政策网站为例展示完整的爬虫代码。请注意实际代码需要根据目标网站的具体结构进行调整。import time import json from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException, NoSuchElementException class GovPolicyCrawler: def __init__(self, headlessFalse): 初始化爬虫创建浏览器驱动。 :param headless: 是否使用无头模式不显示浏览器界面 chrome_options webdriver.ChromeOptions() if headless: chrome_options.add_argument(--headless) # 无头模式后台运行 chrome_options.add_argument(--disable-gpu) # 禁用GPU加速某些系统需要 chrome_options.add_argument(--no-sandbox) # Linux系统下可能需要 chrome_options.add_argument(--disable-dev-shm-usage) # 解决共享内存问题 # 禁用图片加载显著加快页面加载速度 prefs {profile.managed_default_content_settings.images: 2} chrome_options.add_experimental_option(prefs, prefs) # 初始化Service和Driver # 请确保chromedriver已在PATH中或在此指定路径Service(‘./chromedriver’) self.driver webdriver.Chrome(optionschrome_options) self.wait WebDriverWait(self.driver, 15) # 全局显式等待对象15秒超时 self.driver.implicitly_wait(5) # 全局隐式等待作为后备 def crawl(self, start_url, max_pages5): 主爬取流程。 :param start_url: 政策列表起始页URL :param max_pages: 最大爬取页数防止意外无限循环 all_policies [] current_page 1 current_url start_url try: while current_page max_pages: print(f正在抓取第 {current_page} 页: {current_url}) # 1. 访问列表页 self.driver.get(current_url) # 2. 等待列表容器加载完成 try: list_container self.wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, .policy-list-container)) ) except TimeoutException: print(f第 {current_page} 页列表容器加载超时可能已无更多页面或网站结构变化。) break # 3. 解析当前页的所有政策条目 policy_items self._parse_list_page() print(f 本页找到 {len(policy_items)} 条政策。) # 4. 遍历每个条目进入详情页抓取 for item in policy_items: policy_detail self._parse_detail_page(item[detail_url]) if policy_detail: # 合并列表页和详情页信息 policy_data {**item, **policy_detail} all_policies.append(policy_data) print(f 已抓取: {policy_data[title]}) # 抓取一条后短暂休息减轻服务器压力 time.sleep(1) # 5. 查找并点击“下一页”按钮 next_page_url self._get_next_page_url() if next_page_url and current_page max_pages: current_url next_page_url current_page 1 # 翻页后休息更长时间 time.sleep(2) else: print(已到达最后一页或达到最大页数限制爬取结束。) break except Exception as e: print(f爬取过程中发生错误: {e}) finally: # 6. 保存数据并退出 self._save_data(all_policies) self.driver.quit() print(f爬虫结束共抓取 {len(all_policies)} 条政策数据。) def _parse_list_page(self): 解析列表页提取每条政策的基本信息标题、链接、发布日期等。 items [] # 使用find_elements定位所有条目这里假设每个条目在li class‘policy-item’里 item_elements self.driver.find_elements(By.CSS_SELECTOR, li.policy-item) for elem in item_elements: try: # 提取标题和详情页链接 title_elem elem.find_element(By.CSS_SELECTOR, a.policy-title) title title_elem.text.strip() detail_url title_elem.get_attribute(href) # 提取发布日期假设在一个class为‘publish-date’的span里 date_elem elem.find_element(By.CSS_SELECTOR, span.publish-date) publish_date date_elem.text.strip() # 提取文号可能没有 try: doc_num_elem elem.find_element(By.CSS_SELECTOR, span.doc-number) doc_number doc_num_elem.text.strip() except NoSuchElementException: doc_number N/A items.append({ title: title, detail_url: detail_url, publish_date: publish_date, doc_number_list: doc_number, # 列表页的文号可能不完整 source_page: self.driver.current_url }) except NoSuchElementException as e: print(f解析列表项时遇到异常结构跳过此项。异常: {e}) continue return items def _parse_detail_page(self, detail_url): 解析政策详情页提取完整信息。 try: self.driver.get(detail_url) # 等待详情页主要内容区域加载 content_wait WebDriverWait(self.driver, 10) content_wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, .policy-detail-content))) # 提取详情页标题可能与列表页略有不同 try: detail_title self.driver.find_element(By.CSS_SELECTOR, h1.detail-title).text.strip() except NoSuchElementException: detail_title self.driver.title # 回退到浏览器标题 # 提取正文内容 content_elem self.driver.find_element(By.CSS_SELECTOR, .policy-detail-content) # 获取所有文本或按段落组织 full_text content_elem.text.strip() # 或者获取内部HTML保留一些格式 # full_html content_elem.get_attribute(innerHTML) # 提取附件链接 attachments [] attachment_links self.driver.find_elements(By.CSS_SELECTOR, .attachments a[href$.pdf], .attachments a[href$.doc], .attachments a[href$.docx]) for link in attachment_links: attachments.append({ name: link.text.strip() or link.get_attribute(href).split(/)[-1], url: link.get_attribute(href) }) # 提取其他元信息如发文机构、主题分类等 meta_info {} try: org_elem self.driver.find_element(By.XPATH, //span[contains(text(),发文机构)]/following-sibling::span) meta_info[issuing_org] org_elem.text.strip() except NoSuchElementException: meta_info[issuing_org] N/A return { detail_title: detail_title, full_text: full_text[:500] ... if len(full_text) 500 else full_text, # 存储摘要或全文 attachments: attachments, meta_info: meta_info } except TimeoutException: print(f详情页加载超时: {detail_url}) return None except Exception as e: print(f解析详情页 {detail_url} 时出错: {e}) return None def _get_next_page_url(self): 获取下一页的URL。策略先尝试找‘下一页’按钮的链接如果没有则尝试构造URL。 try: # 方法1查找带有‘下一页’文本或特定class的链接 next_link self.driver.find_element(By.CSS_SELECTOR, a.next-page, li.next a) return next_link.get_attribute(href) except NoSuchElementException: # 方法2如果网站是规律的分页如 /page/2/可以尝试构造 # 这里需要根据实际情况编写逻辑本例暂不实现 # current_url self.driver.current_url # if ‘page1’ in current_url: # return current_url.replace(‘page1’, ‘page2’) pass return None def _save_data(self, data): 将数据保存为JSON文件。 filename fgov_policies_{time.strftime(%Y%m%d_%H%M%S)}.json with open(filename, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2) print(f数据已保存至文件: {filename}) if __name__ __main__: # 使用示例 # 请替换为真实的、允许爬取的政府网站政策列表页URL START_URL https://www.example.gov.cn/zwgk/zcfg/list.html crawler GovPolicyCrawler(headlessTrue) # 生产环境建议使用无头模式 crawler.crawl(start_urlSTART_URL, max_pages3) # 先测试抓取3页代码关键点解析类封装使用GovPolicyCrawler类将功能模块化使代码结构清晰易于管理和扩展。浏览器选项ChromeOptions用于配置浏览器行为。--headless在服务器运行时非常有用。禁用图片加载能极大提升爬取速度。混合等待策略同时设置了全局隐式等待5秒和针对特定条件的显式等待15秒。显式等待优先级更高用于关键节点。健壮的解析在_parse_list_page和_parse_detail_page中使用了try...except块来捕获NoSuchElementException。这样即使某个页面的某个元素缺失或结构略有不同爬虫也不会崩溃而是记录错误并继续处理其他条目。礼貌性延迟在抓取每条详情(time.sleep(1))和翻页后(time.sleep(2))添加了延迟。这是非常重要的网络礼仪可以显著降低对目标服务器的请求压力避免被识别为恶意攻击。数据存储将数据保存为带时间戳的JSON文件便于区分不同批次的数据。JSON格式结构化好易于后续用Python进行数据分析。异常处理与资源清理主流程包裹在try...except中并在finally块中确保浏览器驱动被关闭避免资源泄漏。6. 高级技巧、反爬应对与伦理规范6.1 提升爬虫稳定性与效率的技巧即使有了基础代码在实际运行中你仍会遇到各种问题。下面分享几个提升爬虫鲁棒性和效率的进阶技巧。处理弹窗和登录有些网站在访问时会有弹窗。可以在初始化选项中加入参数来禁用弹窗。chrome_options.add_argument(--disable-popup-blocking) prefs { profile.default_content_setting_values.notifications: 2, # 禁用通知 } chrome_options.add_experimental_option(prefs, prefs)如果网站需要简单登录可以考虑在代码中自动填充仅限公开测试账号或已获授权的场景。但涉及复杂验证码或动态令牌的登录通常超出了简单爬虫的范围需考虑其他方案或人工介入。使用User-Agent轮换虽然Selenium使用真实浏览器但其默认的User-Agent可能带有HeadlessChrome等特征。我们可以随机轮换UA使其更像普通浏览器。import random user_agents [ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ..., Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 ..., # ... 添加更多常见UA ] chrome_options.add_argument(f--user-agent{random.choice(user_agents)})应对页面懒加载很多网站为了性能会采用“滚动到底部加载更多”的懒加载方式。Selenium可以模拟滚动。# 滚动到页面底部 last_height driver.execute_script(return document.body.scrollHeight) while True: driver.execute_script(window.scrollTo(0, document.body.scrollHeight);) time.sleep(2) # 等待新内容加载 new_height driver.execute_script(return document.body.scrollHeight) if new_height last_height: break last_height new_height使用浏览器指纹干扰一些高级反爬会检测浏览器指纹。我们可以添加一些参数来使其更“普通”。chrome_options.add_argument(--disable-blink-featuresAutomationControlled) chrome_options.add_experimental_option(excludeSwitches, [enable-automation]) chrome_options.add_experimental_option(useAutomationExtension, False) # 在启动后执行JS覆盖navigator.webdriver属性 driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, { source: Object.defineProperty(navigator, webdriver, { get: () undefined }); })6.2 常见问题排查与调试记录在开发爬虫时你一定会遇到各种报错。这里记录几个最常见的问题及其解决方法。问题一selenium.common.exceptions.WebDriverException: Message: unknown error: cannot find Chrome binary原因Selenium找不到Chrome浏览器的安装位置。解决确保Chrome已正确安装。或者在ChromeOptions中指定Chrome二进制文件路径chrome_options.binary_location rC:\Program Files\Google\Chrome\Application\chrome.exe # Windows示例问题二selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version XX原因ChromeDriver版本与已安装的Chrome浏览器版本不匹配。解决这是最经典的问题。严格按照前面“环境准备”部分所述检查并下载对应版本的ChromeDriver。问题三元素定位失败抛出NoSuchElementException或等待超时TimeoutException原因页面尚未加载完成元素还未出现。元素定位器CSS选择器/XPath写错了或者网站结构发生了变化。元素在iframe框架内需要先切换进去。元素被遮挡或不可见。排查步骤增加等待时间尝试增加显式等待的超时时间如从10秒加到20秒。验证定位器在浏览器的开发者工具Console中使用document.querySelectorAll(“你的CSS选择器”)或$x(“你的XPath”)来测试定位器是否能找到元素。检查iframe在Elements面板查看目标元素是否在一个iframe标签内。如果是需要使用driver.switch_to.frame(frame_reference)切换到该iframe后才能定位其中的元素。检查元素状态使用EC.visibility_of_element_located而不是EC.presence_of_element_located确保元素不仅存在而且可见。问题四爬虫运行一段时间后突然中断或浏览器崩溃原因可能是内存泄漏、打开的标签页过多或遇到了无法处理的弹窗/JS错误。解决定期重启Driver对于需要长时间运行的任务可以设定抓取一定数量页面后主动driver.quit()并重新初始化一个新的Driver。管理标签页如果打开了新标签页记得在操作完成后用driver.close()关闭它并用driver.switch_to.window(original_window)切回主窗口。添加更全面的异常捕获在关键操作外包裹try-except记录错误并尝试恢复或跳过。调试技巧禁用无头模式开发阶段将headlessFalse亲眼观察浏览器每一步的操作非常直观。截图在出错的地方使用driver.save_screenshot(‘error.png’)保存截图帮助分析页面状态。打印页面源码在关键步骤后打印driver.page_source的一部分查看此时HTML的实际结构。使用time.sleep进行临时调试在怀疑是等待时间不足的地方临时插入time.sleep(5)看问题是否消失。6.3 网络爬虫伦理与法律边界这是所有爬虫开发者必须严肃对待的一课。技术是中立的但使用技术的方式有对错之分。首要原则尊重robots.txt。这个文件是网站所有者与爬虫之间的“君子协议”。明确禁止爬取的目录绝对不要去碰。对于政府公开信息网站通常robots.txt会比较宽松但依然要检查。控制访问频率做“礼貌”的爬虫。我们的代码中已经加入了time.sleep。一个更优的策略是使用随机延迟模拟人类不规律的访问间隔。import random time.sleep(random.uniform(1, 3)) # 在1到3秒之间随机休眠避免在短时间内发起海量请求这会对服务器造成“压力测试”般的冲击可能影响正常用户访问也极易导致你的IP被封锁。识别并遵守网站的使用条款。很多网站会在“服务条款”或“网站声明”中明确禁止未经授权的自动化抓取。在开始大规模爬取前花几分钟阅读这些条款是必要的。数据使用目的。抓取公开的政府政策文件用于个人研究、数据分析或新闻报道通常被认为是合理使用。但如果你将抓取的数据用于商业盈利、发布到竞争性网站或者进行歪曲、篡改就可能涉及侵权甚至违法。识别公开与非公开数据。政府网站上的政策文件、通知公告通常是公开信息。但后台管理系统、需要登录才能查看的个人信息、未公开的统计数据等绝对不属于可爬取的范围。技术手段的边界。我们使用Selenium模拟浏览器这本身是一种自动化工具。但切记不要试图用它来破解验证码、绕过付费墙、或进行登录爆破等恶意行为。这不再是“爬虫”而是“攻击”了。个人体会在我多年的爬虫实践中始终秉持“索取有度”的原则。我会将爬虫的User-Agent设置为包含我的联系方式以便网站管理员在认为访问异常时能联系到我。在代码中设置较长的请求间隔并尽量在服务器流量较低的时段如凌晨运行爬虫。对于重要的项目如果数据量巨大我会考虑联系网站方询问是否有公开的API或数据集可供下载这往往是最友好、最高效的方式。技术让我们有能力获取数据但责任感和法律意识决定了我们能否长久、安全地使用这些数据。