python学习-网络爬虫
本文介绍下
Python
中使用Selenium
进行网络爬虫的基本操作,包括网络爬虫简介、Selenium 简介、环境准备、Selenium基础、页面元素操作、高级操作、处理Cookies、异常处理和数据提取与解析等。供自己以后查漏补缺,也欢迎同道朋友交流学习。
引言
之前介绍的都是运行自己写的程序,但还可以使用网络爬虫
获取别人网站上的信息,并对其进行处理。
本章主要介绍下 Python
中使用 Selenium
进行网络爬虫的基本操作,包括网络爬虫简介、Selenium 简介、环境准备、Selenium基础、页面元素操作、高级操作、处理Cookies、异常处理和数据提取与解析等。
网络爬虫简介
网络爬虫(Web Crawler
),也称为网页蜘蛛(Spider
)或爬虫(Crawler
),是一种自动浏览网络的软件,用于从互联网上下载网页。它的主要任务是抓取网页内容
,以便进行后续的数据处理和分析
。
网络爬虫可以用于多种目的,包括但不限于数据收集
、信息聚合
、搜索引擎构建
等。
- 工作原理:
网络爬虫
从一个或多个种子URL
开始,访问这些页面,提取页面中的链接,然后递归地访问这些链接指向的页面,如此循环,直到满足特定条件(如深度限制
、时间限制
等)。 - 关键技术:包括
URL
管理、内容下载、链接提取、内容解析
和数据存储
等。
Selenium简介
Selenium
是一个开源的自动化测试
工具,广泛用于 Web
应用程序的测试。它提供了一套工具和库,允许开发者模拟
用户与浏览器的交互,实现自动化测试
。
Selenium的作用
- 自动化测试:
Selenium
最初被设计用于自动化Web
应用程序的测试
,它可以模拟用户的各种操作,如点击
、输入
、滚动
等。 - 爬虫工具:由于能够执行
JS
并模拟真实用户行为,它也被用作一种爬虫工具
,尤其是在需要处理JS
渲染的页面时。 - 浏览器自动化:可以自动化浏览器操作,用于
网页截图
、表单填充
、文件上传
等任务。
Selenium的特点
- 跨浏览器支持:支持多种浏览器,包括
Chrome
、Firefox
、Internet Explorer
、Edge
等。 - 跨平台支持:可以在
Windows
、Linux
和Mac OS
上运行。 - 编程语言兼容性:提供了多种语言的绑定,如
Java
、C#
、Python
、Ruby
等。 - 丰富的API:提供了丰富的
API
,可以精确控制浏览器行为。 - 集成WebDriver:通过
WebDriver
协议与浏览器交互,可以启动和停止浏览器,以及执行复杂的浏览器操作。
适用场景
- 自动化测试:对于需要自动化测试 Web 应用程序的场景,
Selenium
是理想的选择。 - 动态内容爬取:对于那些通过
JS
动态加载内容的网站,可以模拟用户行为,获取动态生成的数据。 - 用户行为模拟:需要
模拟
用户登录、表单提交等复杂交互的场景。 - 浏览器兼容性测试:需要测试 Web 应用程序在不同浏览器和不同操作系统上的表现。
环境准备
在开始使用 Selenium
进行自动化测试或网络爬虫之前,需要做好环境的准备工作,包括安装 Selenium
库和配置 WebDriver
。
Selenium库的安装
pip install selenium
WebDriver的安装和配置
我们大部分人都用 chrome 浏览器,那就安装 ChromeDriver
吧
- 下载:访问 ChromeDriver 下载页面,选择与你的
Chrome
浏览器版本相匹配的ChromeDriver
版本进行下载。
下载地址:googlechromelabs.github.io/chrome-for-…
-
解压:下载完成后,解压
ChromeDriver
到一个你记得的目录。 -
配置环境变量(可选):
- 在
Windows
上,将ChromeDriver
的路径
添加到系统的PATH 环境变量
中。 - 在
Mac
或Linux
上,可以在终端中使用export PATH=$PATH:/path/to/chromedriver
命令,将ChromeDriver
的路径添加到PATH
环境变量中。也可以将这行命令添加到.bashrc
或.bash_profile
文件中,以便每次打开终端时自动设置环境变量。
- 在
Selenium基础
Selenium对象和方法概览
Selenium 的核心对象是 WebDriver
,它提供了与浏览器交互的方法。以下是一些基本的 Selenium
对象和方法:
对象或方法 | 说明 |
---|---|
WebDriver | 用于创建 WebDriver 实例,核心对象 ,与浏览器交互。 |
find_element_by_* | 用于定位页面元素,例如 find_element_by_id 、find_element_by_name 等。 |
find_elements_by_* | 返回所有匹配 的元素。 |
get | 加载指定的 URL 。 |
current_url | 获取当前页面的 URL 。 |
title | 获取当前页面的标题 。 |
back | 后退到浏览器历史记录 中的上一个 页面。 |
forward | 前进 到浏览器历史记录中的下一个 页面。 |
refresh | 刷新当前页面。 |
close | 关闭当前窗口。 |
quit | 关闭所有窗口,并结束 WebDriver 会话。 |
浏览器基本操作
- 使用
webdriver.Chrome()
方法来打开浏览器。 - 使用
get(URL)
方法导航到页面。 - 使用
quit()
关闭浏览器。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
# 等待几秒钟以观察效果
time.sleep(10)
# 完成后关闭浏览器
driver.quit()
查看页面元素
查看页面元素对前端来说是小菜一碟,我们可以通过 ID
、Tag Name
、Class
、XPath
、CSS Selector
等定位元素。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
# 通过标签名定位
tag_element = driver.find_element(By.TAG_NAME, 'nav')
print('@@@ 通过标签名定位', tag_element)
# 输出:@@@ 通过标签名定位 <selenium.webdriver.remote.webelement.WebElement (session="ffe53878aee56d8bbc922cbdad818380", element="f.495E49F864D91F7A7087BA0622B7C8D6.d.F0348429DF22E18BA211FD04F7F18038.e.19")>
# 通过ID定位
id_element = driver.find_element(By.ID, 'js-flash-container')
print('@@@ 通过ID定位', id_element)
# 输出:@@@ 通过ID定位 <selenium.webdriver.remote.webelement.WebElement (session="f1cfb9ee35f2481612bb128c37685cef", element="f.DDDA952C195AFCAD3B0A84E3A0F35B1C.d.CCA8F91E0BA7467AF81CCED217733054.e.19")>
# 通过Class定位
class_element = driver.find_element(By.CLASS_NAME, 'color-bg-subtle')
print('@@@ 通过Class定位', class_element)
# 输出:@@@ 通过Class定位 <selenium.webdriver.remote.webelement.WebElement (session="f1cfb9ee35f2481612bb128c37685cef", element="f.DDDA952C195AFCAD3B0A84E3A0F35B1C.d.CCA8F91E0BA7467AF81CCED217733054.e.20")>
# 等待几秒钟以观察效果
time.sleep(10)
# 完成后关闭浏览器
driver.quit()
页面元素操作
- 获取元素文本:使用
element.text
属性。 - 点击:使用
element.click()
方法。 - 输入文本:使用
element.send_keys(text)
方法。 - 提交表单:使用
element.submit()
方法。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
# 通过Class定位
class_element = driver.find_element(By.CLASS_NAME, 'color-bg-subtle')
# 获取元素文本
print(class_element.text)
# 输出:
# Topics
# Browse popular topics on GitHub.
# 点击
search_element = driver.find_element(By.CLASS_NAME, 'header-search-button')
search_element.click()
# 输入文本
input_element = driver.find_element(By.ID, 'query-builder-test')
input_element.send_keys('hello')
time.sleep(2)
# 提交表单
input_element.submit()
# 等待几秒钟以观察效果
time.sleep(10)
# 完成后关闭浏览器
driver.quit()
录入文本效果如下图:
提交表单后效果如下图:
高级操作
等待机制
- 显式等待(WebDriverWait):
显式等待
允许你指定等待某个条件成立后再继续执行代码。这是处理动态内容加载非常有效的方式。
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
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
try:
# 显式等待(WebDriverWait)
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "query-builder-test"))
)
finally:
# 等待几秒钟以观察效果
time.sleep(10)
# 完成后关闭浏览器
driver.quit()
- 隐式等待:隐式等待设置了一个
全局等待时间
,Selenium
会等待直到指定的时间结束或者找到元素为止。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
driver.implicitly_wait(5) # 等待最多5秒
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
# 等待几秒钟以观察效果
time.sleep(10)
# 完成后关闭浏览器
driver.quit()
滚动和定位可视区域
使用 execute_script
去执行 window.scrollTo
和 element.scrollIntoView()
去滚动到固定位置或者元素。
滚动到某个元素:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
driver.implicitly_wait(5) # 等待最多5秒
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
# 滚动到元素
footer_element = driver.find_element(By.CLASS_NAME, 'footer')
driver.execute_script("arguments[0].scrollIntoView();", footer_element)
# 等待几秒钟以观察效果
time.sleep(10)
# 完成后关闭浏览器
driver.quit()
滚动到固定位置:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
driver.implicitly_wait(5) # 等待最多5秒
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
time.sleep(2)
# 滚动Y轴到250px
driver.execute_script("window.scrollTo(0, 250);")
time.sleep(2)
# 滚动Y轴到650px
driver.execute_script("window.scrollTo(0, 650);")
time.sleep(2)
# 滚动Y轴到0px
driver.execute_script("window.scrollTo(0, 0);")
# 等待几秒钟以观察效果
time.sleep(5)
# 完成后关闭浏览器
driver.quit()
处理Cookies
在 Selenium
中,Cookies
是一种用于在浏览器中存储用户信息的机制。它们通常用于保持用户登录状态、跟踪用户行为等。
操作Cookies的方法
- 获取Cookies:使用
driver.get_cookies()
方法获取当前页面的所有Cookies。 - 获取单个Cookie:使用
driver.get_cookie(name)
方法获取一个Cookie。 - 添加单个Cookie:使用
driver.add_cookie(cookie_dict)
方法添加一个Cookie。 - 修改单个Cookie:使用
driver.add_cookie(cookie_dict)
方法修改一个Cookie。 - 删除单个Cookie:使用
driver.delete_cookie(name)
方法删除一个Cookie。 - 删除所有Cookies:使用
driver.delete_all_cookies()
方法删除所有Cookies。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
# 获取所有cookies
cookies = driver.get_cookies()
print('@@@ 获取所有cookies', cookies)
# 输出:@@@ 获取cookies [{'domain': '.github.com', 'expiry': 1765019116, 'httpOnly': True, 'name': 'logged_in', 'path': '/', 'sameSite': 'Lax', 'secure': True, 'value': 'no'}, {'domain': '.github.com', 'expiry': 1765019116, 'httpOnly': False, 'name': '_octo', 'path': '/', 'sameSite': 'Lax', 'secure': True, 'value': 'GH1.1.31591717.1733483116'}, {'domain': '.github.com', 'httpOnly': False, 'name': 'tz', 'path': '/', 'sameSite': 'Lax', 'secure': True, 'value': 'Asia%2FShanghai'}, {'domain': '.github.com', 'httpOnly': False, 'name': 'preferred_color_mode', 'path': '/', 'sameSite': 'Lax', 'secure': True, 'value': 'light'}, {'domain': '.github.com', 'httpOnly': False, 'name': 'cpu_bucket', 'path': '/', 'sameSite': 'Lax', 'secure': True, 'value': 'md'}, {'domain': 'github.com', 'httpOnly': True, 'name': '_gh_sess', 'path': '/', 'sameSite': 'Lax', 'secure': True, 'value': 'PoRbFihouKYXdyt2mjxNtNn0pPTtfrhoSduAn8MRASRmODZG9gpwBuTHT8Lt50Zf0POJBToR8W%2B02PCtYS4eu%2B5UwCP0KNbX8olxQ8C5gnJOx9gAs%2BhITgWL69UeCfMNFcI01eYJJ79tWh8eCLwkK536kJxM0kG6XXnmK5Zoj%2FPlH%2BVvElfJpAD7X0BFJ8GtZ4VYEe53cd8RWQYuPQ81m60kYBcnNyo%2BY%2BLdi5BafxVE8mAUYCrGIbXu1%2BDdz%2BvoIjgfYiGtiFS6QdnYwcw5yA%3D%3D--AKNcVUGMAiLpSyPi--He8MHb1zSfqYj4YW3aIYKw%3D%3D'}]
# 获取单个Cookie
cookie_logged_in = driver.get_cookie('logged_in')
print('@@@ 获取单个cookie', cookie_logged_in)
# 输出:@@@ 获取单个cookie {'domain': '.github.com', 'expiry': 1765019385, 'httpOnly': True, 'name': 'logged_in', 'path': '/', 'sameSite': 'Lax', 'secure': True, 'value': 'no'}
# 添加单个Cookie
driver.add_cookie({"name": "log", "value": "日志"})
log_cookie = driver.get_cookie('log')
print(log_cookie)
# 输出:{'domain': 'github.com', 'httpOnly': False, 'name': 'log', 'path': '/', 'sameSite': 'Lax', 'secure': True, 'value': '日志'}
# 修改单个Cookie
log_cookie['value'] = '@@@@日志22222'
driver.add_cookie(log_cookie)
print(driver.get_cookie('log'))
# 输出:{'domain': '.github.com', 'httpOnly': False, 'name': 'log', 'path': '/', 'sameSite': 'Lax', 'secure': True, 'value': '@@@@日志22222'}
# 删除单个Cookie
driver.delete_cookie("log")
print(driver.get_cookie('log'))
# 输出:None
# 删除全部Cookies
driver.delete_all_cookies()
print(driver.get_cookies())
# 输出:[]
# 等待几秒钟以观察效果
time.sleep(10)
# 完成后关闭浏览器
driver.quit()
异常处理
在使用 Selenium
进行自动化测试时,异常处理是一个重要的环节,它可以帮助我们确保测试脚本的稳定性和可靠性。
常见Selenium异常
- NoSuchElementException:当
Selenium
尝试查找页面上不存在
的元素时触发。 - StaleElementReferenceException:当元素在查找后被页面
重新加载或刷新
,导致元素引用失效时触发。 - TimeoutException:当
WebDriver
等待某个条件满足的时间超过设定的超时
时间时触发。 - ElementNotInteractableException:当元素
不可交互
(如被遮挡或不可见)时触发。 - InvalidSelectorException:使用
无效的选择器
查找元素时抛出。 - InvalidElementStateException:尝试在
元素状态不允许
的情况下执行操作时抛出
异常捕获和处理
使用 try-except
语句捕获并处理异常,确保测试脚本的稳定运行。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
try:
# 尝试执行的代码,可能抛出异常
element = driver.find_element(By.ID, "non-existent-element")
element.click()
except NoSuchElementException:
# 处理NoSuchElementException异常
print("元素未找到")
except Exception as e:
# 处理其他类型的异常
print("发生其他异常:", e)
finally:
# 关闭浏览器
driver.quit()
# 输出:元素未找到
数据提取与解析
在网络爬虫中,数据提取和解析是核心任务之一。
提取HTML内容
可以使用 page_source
属性来获取当前页面的 HTML
内容。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
# 获取页面的HTML内容
html_content = driver.page_source
# 打印HTML内容
print(html_content)
# 输出:<html> xxx </html>
# 等待几秒钟以观察效果
time.sleep(10)
# 完成后关闭浏览器
driver.quit()
使用BeautifulSoup进行HTML解析
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from bs4 import BeautifulSoup
import time
# 如果配置了全局就不需要写chrome_driver_path
chrome_driver_path = '../chromedriver-mac-x64/chromedriver'
# 创建 Service 对象
service = Service(executable_path=chrome_driver_path)
# 打开浏览器
# 如果配置了全局就不需要写service
driver = webdriver.Chrome(service=service)
# 使用driver来控制Chrome浏览器了
driver.get('https://github.com/topics')
# 获取页面的HTML内容
html_content = driver.page_source
soup = BeautifulSoup(html_content, 'html.parser')
# 提取标题
title = soup.find('title').text
# 提取所有链接
links = soup.find_all('a')
for link in links:
print(link.get('href'))
# 提取特定类名的元素
elements = soup.find_all(class_='topic-box')
for element in elements:
print(element.text)
# 等待几秒钟以观察效果
time.sleep(10)
# 完成后关闭浏览器
driver.quit()
JSON数据提取
如果 JSON
数据是通过 JS
动态加载的,需要使用 Selenium
等待数据加载完成,然后使用 execute_script
方法来获取 JS
变量的值。
# 假设页面中有一个JavaScript变量var myData = {name: "niunai", age: 33, city: "上海"};
# 使用execute_script获取JSON数据
json_data = driver.execute_script("return myData;")
# 将获取的数据转换为Python字典
data = json.loads(json_data)
# 访问数据
print(data['name']) # 输出: niunai
法律和道德问题
在使用 Selenium
进行网络爬虫
或自动化测试
时,遵守法律和道德规范是非常重要的。
遵守Robots协议
- Robots协议:这是一个网站通过
robots.txt
文件提供的指导,告诉爬虫哪些页面可以访问,哪些页面不应该访问。robots.txt
通常位于网站的根目录下,例如:https://www.baidu.com/robots.txt
。 - 遵守协议:在使用
Selenium
时,应该检查并遵守目标网站的robots.txt
文件。不要尝试访问被禁止的页面或目录。
尊重版权和隐私
- 版权:在爬取和使用网站内容时,必须尊重
版权法
。不要复制、分发或使用受版权保护的内容,除非你已经获得了版权所有者的明确许可。 - 隐私:尊重用户的
隐私权
。不要收集、存储或使用用户的个人信息,除非已经获得了用户的同意,并且符合相关的隐私保护法规。
避免对网站造成过大负担
- 请求频率:不要发送过多的请求到同一个网站,这可能会导致
服务器过载
,影响网站的正常运行。合理设置请求间隔,以减轻对网站服务器的压力。 - 分布式爬取:如果需要
爬取
大量数据,考虑使用分布式爬虫系统
,分散请求负载。 - 服务器时间:尽量
避免
在网站的高峰时段
进行爬取,以减少对网站性能的影响。
申明
本文爬取的是 https://github.com/topics
页面,仅供学习测试,请勿用于非法用途。
python学习专栏系列
- python学习-基础学习1
- python学习-基础学习2
- python学习-基础学习3
- python学习-面向对象编程1
- python学习-面向对象编程2
- python学习-文件读写
- python学习-程序异常处理
- python学习-正则
- python学习-处理word文档
- python学习-处理pdf文档
- python学习-处理excel文档
- python学习-处理csv文档
- python学习-使用matplotlib绘制图表
- python学习-处理JSON数据
- python学习-SQLite数据库
- python学习-多线程处理
- python学习-网络爬虫