当前位置: 首页 > news >正文

Python爬虫实战:Selenium模拟操作爬取马蜂窝旅游攻略

准备工作:安装与配置

  1. 安装必要的库
    使用pip安装Selenium库:

    pip install selenium

    同时,我们通常也会使用BeautifulSouplxml来解析HTML,以及pandas等库来保存数据,你可以按需安装:

    pip install beautifulsoup4 pandas
  2. 下载浏览器驱动
    Selenium需要一个浏览器驱动来操作浏览器。以Chrome为例:

    • 查看你的Chrome浏览器版本(在浏览器地址输入 chrome://version/)。

    • 从 ChromeDriver官网 或 国内镜像 下载对应版本的ChromeDriver。

    • 将下载的chromedriver executable文件放在一个指定目录,并记住路径(如/path/to/chromedriver)。或者,你可以将其添加到系统环境变量PATH中,这样在代码中就不需要指定路径了。

💡 核心步骤与代码示例

下面是一个使用Selenium爬取马蜂窝旅游攻略的基本步骤和代码框架。

步骤 1: 导入库并启动浏览器

from selenium import webdriver
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
import time
import pandas as pd# 指定ChromeDriver路径(如果没添加到PATH)
driver = webdriver.Chrome(executable_path='/path/to/your/chromedriver')  # 对于旧版本Selenium
# 如果Selenium版本较新(>=4.11.2),且ChromeDriver已在PATH中,可以简写为:
# driver = webdriver.Chrome()# 如果需要无头模式(不打开浏览器界面)、设置用户代理等,可以添加选项:
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headless')  # 无头模式,可选
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--user-agent=Your_Custom_User_Agent_String')  # 设置User-Agent,可选
# 然后使用 options 启动:
# driver = webdriver.Chrome(options=chrome_options)
  • 无头模式 (Headless Mode): 在后台运行浏览器,不显示图形界面,节省资源8。

  • User-Agent: 模拟真实浏览器的请求头,有助于规避一些反爬措施2。

步骤 2: 打开目标页面并等待元素加载

现代网页大量使用Ajax动态加载内容,直接获取页面源码可能无法得到完整数据。必须使用等待机制

# 目标URL(以马蜂窝某地攻略列表页为例)
url = 'https://www.mafengwo.cn/mdd/'driver.get(url)  # 导航到页面# 显式等待 - 等待某个关键元素加载完成(例如攻略列表的容器)
try:# 设置等待超时时间,例如10秒wait = WebDriverWait(driver, 10)# 假设攻略列表项的父容器class是 '.post-list'element_present = EC.presence_of_element_located((By.CSS_SELECTOR, '.post-list'))wait.until(element_present)print("页面主要元素加载完成")
except TimeoutException:print("等待元素超时!")driver.quit()# 可以进行错误处理或退出# 隐式等待(可选,但不推荐与显式等待混用)
# driver.implicitly_wait(10)  # 在查找任何元素时,如果未立即找到,会等待最多10秒
关键点:
  • 显式等待 (WebDriverWait): 针对特定条件进行等待,更灵活可靠,推荐使用3。

  • 隐式等待 (implicitly_wait): 设置一个全局的等待时间,对所有find_element操作生效。

步骤 3: 定位元素并提取数据

一旦页面加载完成,你就可以查找所需的元素并提取信息了。

# 假设我们已经成功等待到了列表页的加载
# 查找所有攻略项(根据实际网页结构调整选择器)
strategy_items = driver.find_elements(By.CSS_SELECTOR, '.post-item')  # 使用CSS选择器定位,返回WebElement列表
# 也可以用By.CLASS_NAME, By.XPATH等,例如:
# strategy_items = driver.find_elements(By.XPATH, '//div[@class="post-item"]')data_list = []  # 用于存储提取的数据for item in strategy_items:try:# 在单个攻略项WebElement中继续查找元素title_elem = item.find_element(By.CSS_SELECTOR, 'h2 a')  # 查找标题链接title = title_elem.textlink = title_elem.get_attribute('href')# 查找作者(假设class为author)author_elem = item.find_element(By.CLASS_NAME, 'author')author = author_elem.text# 查找浏览量/评论数等(需要查看实际网页结构)# view_count = item.find_element(By.CLASS_NAME, 'view-count').textprint(f"标题: {title}, 链接: {link}, 作者: {author}")data_list.append({'标题': title, '链接': link, '作者': author})except NoSuchElementException as e:# 如果某个元素在某些项中找不到,跳过此项或记录错误print(f"在项中找不到元素: {e}")continue# 如果数据量大或需要分页,通常需要处理翻页
# 查找"下一页"按钮并点击,然后循环上述过程
try:next_page_button = driver.find_element(By.CSS_SELECTOR, '.pg-next')  # 下一页按钮的选择器if next_page_button.is_enabled():next_page_button.click()# 点击后需要再次等待新页面加载!# time.sleep(2)  # 简单等待,但不推荐# 最好再次使用WebDriverWait等待新列表出现# 然后再次执行提取数据的循环
except NoSuchElementException:print("已是最后一页或找不到下一页按钮")

定位元素常用方法

定位方式示例代码说明
By.IDdriver.find_element(By.ID, "su")通过元素的id属性定位
By.NAMEdriver.find_element(By.NAME, "wd")通过元素的name属性定位
By.CLASS_NAMEdriver.find_element(By.CLASS_NAME, "className")通过元素的class属性定位
By.TAG_NAMEdriver.find_element(By.TAG_NAME, "div")通过元素的标签名定位
By.LINK_TEXTdriver.find_element(By.LINK_TEXT, "地图")通过链接的完整文本定位
By.PARTIAL_LINK_TEXTdriver.find_element(By.PARTIAL_LINK_TEXT, "地")通过链接的部分文本定位
By.CSS_SELECTORdriver.find_element(By.CSS_SELECTOR, "#id .class > a")常用,通过CSS选择器定位
By.XPATHdriver.find_element(By.XPATH, "//div[@id='id']//a[@class='class']")强大常用,通过XPath表达式定位5

步骤 4: 处理动态内容(滚动、Ajax等)

有些内容可能在滚动页面后才加载。

# 模拟滚动到页面底部(加载更多内容)
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 滚动后需要等待新内容加载
time.sleep(2)  # 简单处理,理想情况下应用WebDriverWait# 或者滚动到特定元素
element = driver.find_element(By.ID, "some-element")
driver.execute_script("arguments[0].scrollIntoView();", element)

步骤 5: 数据存储与浏览器退出

提取完数据后,将其保存并关闭浏览器。

# 将数据保存为DataFrame并写入CSV文件:cite[10]
if data_list:df = pd.DataFrame(data_list)df.to_csv('mafengwo_strategies.csv', index=False, encoding='utf-8-sig') # utf-8-sig避免中文乱码print("数据已保存到 mafengwo_strategies.csv")# 关闭浏览器
driver.quit()

⚠️ 重要注意事项

  1. 反爬虫机制2:

    • User-Agent: 设置真实的User-Agent。

    • 行为模式: 避免过快过频的请求,在操作间添加随机延时(time.sleep(random.uniform(1, 3)))。

    • 代理IP: 如果IP被限制,可以考虑使用代理池。

    • 验证码: 如果遇到验证码,可能需要人工处理或使用专门的识别服务。

    • 登录状态: 如需爬取登录后内容,可用Selenium模拟登录并保存Cookies。

  2. 网页结构变化: 网站前端更新可能导致你的选择器失效,需要定期维护代码。

  3. 法律与道德规范8:

    • 遵守robots.txt: 查看马蜂窝的robots.txt文件(通常是 https://www.mafengwo.cn/robots.txt),尊重网站不允许爬取的目录。

    • 合理使用: 爬取数据用于个人学习或研究,不要用于商业用途或对网站造成过大负载。

    • 尊重版权: 注意数据的版权问题。

  4. 性能优化: 对于大规模爬取,考虑使用Scrapy+Selenium的组合1,或者异步等更高效的方式。

💎 更完整的代码片段

这是一个整合了上述部分要点的、针对马蜂窝攻略列表页的更完整示例代码框架请注意: 实际网页结构可能已变化,CSS选择器#container > div:nth-child(6) > div > div.poi-list > ul > li需要你根据实际情况通过浏览器开发者工具检查并修改!):

from selenium import webdriver
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
import time
import pandas as pd
from selenium.webdriver.chrome.options import Optionsdef crawl_mafengwo_strategies():# 设置Chrome选项(可选)chrome_options = Options()# chrome_options.add_argument('--headless')  # 开启无头模式# chrome_options.add_argument('--disable-blink-features=AutomationControlled')# chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])# chrome_options.add_experimental_option('useAutomationExtension', False)# 启动浏览器driver = webdriver.Chrome(options=chrome_options)# driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")wait = WebDriverWait(driver, 10)all_data = []base_url = "https://www.mafengwo.cn/mdd/"try:driver.get(base_url)# 等待页面加载wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".hot-list")))# 模拟滚动driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")time.sleep(2)# 查找热门城市/目的地(示例选择器,需调整)destinations = driver.find_elements(By.CSS_SELECTOR, ".hot-list .item")for dest in destinations:try:name_elem = dest.find_element(By.TAG_NAME, "a")dest_name = name_elem.textdest_link = name_elem.get_attribute('href')print(f"目的地: {dest_name}, 链接: {dest_link}")all_data.append({"目的地": dest_name, "链接": dest_link})except NoSuchElementException:continue# 处理分页(如果存在)# next_page_selector = '.pg-next'  # 示例选择器# page_num = 1# max_pages = 3  # 限制爬取页数# while page_num < max_pages:#     try:#         next_btn = driver.find_element(By.CSS_SELECTOR, next_page_selector)#         if 'disabled' in next_btn.get_attribute('class'):#             break#         next_btn.click()#         wait.until(EC.staleness_of(destinations[0])) # 等待旧元素失效#         # 重新获取列表#         destinations = driver.find_elements(By.CSS_SELECTOR, ".hot-list .item")#         # ... 提取新页数据 ...#         page_num += 1#         time.sleep(1)#     except (NoSuchElementException, TimeoutException):#         breakexcept Exception as e:print(f"爬取过程中发生错误: {e}")finally:driver.quit() # 确保浏览器最终被关闭# 保存数据if all_data:df = pd.DataFrame(all_data)df.to_csv('mafengwo_destinations.csv', index=False, encoding='utf-8-sig')print(f"成功爬取 {len(all_data)} 条数据并已保存。")else:print("未爬取到数据。")if __name__ == "__main__":crawl_mafengwo_strategies()

最重要的一步:使用浏览器的开发者工具(F12) 仔细检查马蜂窝网站的实际HTML结构,并据此更新代码中的元素选择器(如CSS选择器、XPath)。这是Selenium爬虫成功的关键。

http://www.dtcms.com/a/349411.html

相关文章:

  • 神经网络与梯度算法:深度学习的底层逻辑与实战解析
  • Python办公——爬虫百度翻译网页版(自制翻译小工具——进阶更新版)
  • Python爬虫框架设计:类封装与工程化实践​
  • Linux驱动开发笔记(七)——并发与竞争(下)——自旋锁信号量互斥体
  • 计算机网络课堂笔记
  • frp基础知识
  • React 学习笔记2 props、refs
  • 消息中间件RabbitMQ03:结合WebAPI实现点对点(P2P)推送和发布-订阅推送的Demo
  • 从C语言到数据结构:保姆级顺序表解析
  • 使用OpenSSL生成自签名证书
  • 基于PyTorch深度学习遥感影像地物分类与目标检测、分割及遥感影像问题深度学习优化
  • 逆向抄数工程师能力矩阵:设备操作(±0.05mm 精度)× 曲面重构 ×GDT 公差分析
  • C++|UDP通讯使用总结
  • Fluent Bit系列:字符集转码测试(下)
  • Dify 从入门到精通(第 55/100 篇):Dify 的模型微调(进阶篇)
  • Devops之Jenkins:Jenkins服务器中的slave节点是什么?我们为什么要使用slave节点?如何添加一个windows slave节点?
  • 如何监控ElasticSearch的集群状态?
  • Fluent Bit系列:字符集转码测试(上)
  • LengthFieldBasedFrameDecoder 详细用法
  • Error ratio tests for 200 Gb/s per lane ISLs using PMAmeasurements
  • 李沐-第十章-实现Seq2SeqAttentionDecoder时报错
  • 什么是事件循环(Event Loop)?浏览器和 Node.js 中的事件循环有什么区别?
  • springboot整合druid(多数据源配置)
  • Python_occ 学习记录 | 阵列
  • 李沐-第十章-训练Seq2SeqAttentionDecoder报错
  • 十九、云原生分布式存储 CubeFS
  • 剧本杀APP系统开发:打造多元化娱乐生态的先锋力量
  • Go编写的轻量文件监控器. 可以监控终端上指定文件夹内的变化, 阻止删除,修改,新增操作. 可以用于AWD比赛或者终端应急响应
  • TensorFlow深度学习实战(34)——TensorFlow Probability
  • GO学习记录八——多文件封装功能+redis使用