基础知识
Python基础:熟悉Python语言的基本语法,包括变量、数据类型(字符串、列表、字典等)、条件语句、循环、函数定义等
1. 变量
在Python中,变量不需要声明类型,直接赋值即可。
x = 10 # 整数 y = 3.14 # 浮点数 name = "Alice" # 字符串 is_student = True # 布尔值
2. 数据类型
基本数据类型
- 整数 (int):表示整数值。
- 浮点数 (float):表示小数值。
- 字符串 (str):表示文本。
- 布尔值 (bool):表示真 (True) 或假 (False)。
age = 25 height = 5.9 name = "John Doe" is_active = False
复合数据类型
- 列表 (list):有序的可变集合。
- 元组 (tuple):有序的不可变集合。
- 字典 (dict):无序的键值对集合。
- 集合 (set):无序且不重复的元素集合。
# 列表 fruits = ["apple", "banana", "cherry"] # 元组 coordinates = (10, 20) # 字典 person = {"name": "Alice", "age": 25, "city": "New York"} # 集合 unique_numbers = {1, 2, 3, 4, 5}
3. 条件语句
条件语句用于根据不同的条件执行不同的代码块。
age = 20 if age < 18: print("未成年") elif age >= 18 and age < 60: print("成年") else: print("老年")
4. 循环
循环用于重复执行某段代码。
for 循环
# 遍历列表 fruits = ["apple", "banana", "cherry"] for fruit in fruits: print(fruit) # 使用range函数 for i in range(5): # 0到4 print(i)
while 循环
count = 0 while count < 5: print(count) count += 1
5. 函数定义
函数用于封装一段可重用的代码。
def greet(name): return f"Hello, {name}!" print(greet("Alice")) # 带默认参数的函数 def greet_with_default(name="Guest"): return f"Hello, {name}!" print(greet_with_default()) print(greet_with_default("Bob"))
6. 列表推导式
列表推导式是一种简洁的创建列表的方法。
squares = [x**2 for x in range(10)] print(squares) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
7. 字典推导式
字典推导式用于创建字典。
squares_dict = {x: x**2 for x in range(5)} print(squares_dict) # 输出: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
8. 文件操作
读写文件是常见的操作。
# 写入文件 with open("example.txt", "w") as file: file.write("Hello, World!") # 读取文件 with open("example.txt", "r") as file: content = file.read() print(content)
9. 异常处理
异常处理用于捕获和处理运行时错误。
try: result = 10 / 0 except ZeroDivisionError: print("除零错误") finally: print("无论是否发生异常,都会执行这里")
10. 模块导入
模块导入用于使用其他文件中的代码。
import math print(math.sqrt(16)) # 输出: 4.0 # 导入特定函数 from math import sqrt print(sqrt(16)) # 输出: 4.0
2、网络请求:了解HTTP协议的基础知识,包括GET和POST请求,以及如何使用Python发送这些请求。
HTTP协议基础
1. HTTP协议
HTTP(HyperText Transfer Protocol)是用于从Web服务器传输超文本到本地浏览器的传输协议。它是一个应用层协议,基于客户端-服务器模型。
2. 请求方法
HTTP协议定义了多种请求方法,其中最常用的是GET和POST:
- GET:用于请求指定的资源。GET请求应该只用于获取数据,而不应该用于修改服务器上的数据。GET请求的参数通常附加在URL后面。
- POST:用于向指定资源提交数据,通常用于提交表单数据或上传文件。POST请求的参数放在请求体中。
3. 请求和响应
- 请求:客户端(如浏览器)向服务器发送的请求,包含请求行、请求头和请求体。
- 响应:服务器返回给客户端的响应,包含状态行、响应头和响应体。
使用Python发送HTTP请求
1. 使用
requests
库
requests
库是Python中最常用的HTTP库之一,简单易用且功能强大。首先需要安装requests
库:pip install requests
2. 发送GET请求
发送GET请求非常简单,只需要调用
requests.get()
方法。import requests # 发送GET请求 response = requests.get('https://api.example.com/data') # 检查请求是否成功 if response.status_code == 200: # 打印响应内容 print(response.text) else: print(f"请求失败,状态码: {response.status_code}")
3. 发送带参数的GET请求
可以在URL后面附加查询参数,或者使用
params
参数传递字典。import requests # 定义查询参数 params = { 'key1': 'value1', 'key2': 'value2' } # 发送GET请求 response = requests.get('https://api.example.com/data', params=params) # 检查请求是否成功 if response.status_code == 200: # 打印响应内容 print(response.text) else: print(f"请求失败,状态码: {response.status_code}")
4. 发送POST请求
发送POST请求时,通常需要在请求体中包含数据。可以使用
data
参数传递字典。import requests # 定义请求体数据 data = { 'username': 'user123', 'password': 'pass456' } # 发送POST请求 response = requests.post('https://api.example.com/login', data=data) # 检查请求是否成功 if response.status_code == 200: # 打印响应内容 print(response.text) else: print(f"请求失败,状态码: {response.status_code}")
5. 处理响应
requests
库提供了多种方法来处理响应,包括获取响应状态码、响应头和响应体。import requests # 发送GET请求 response = requests.get('https://api.example.com/data') # 获取状态码 status_code = response.status_code print(f"状态码: {status_code}") # 获取响应头 headers = response.headers print(f"响应头: {headers}") # 获取响应体 text = response.text json_data = response.json() # 如果响应内容是JSON格式 print(f"响应内容: {text}") print(f"JSON数据: {json_data}")
3、HTML/CSS:理解网页的结构,知道如何通过标签和CSS选择器定位页面元素。
1. HTML (HyperText Markup Language)
1.1 基本结构
HTML 是一种标记语言,用于创建网页。一个基本的HTML文档结构如下:
<!DOCTYPE html> <html> <head> <title>网页标题</title> </head> <body> <h1>主标题</h1> <p>这是一个段落。</p> <a href="https://example.com">链接</a> <img src="image.jpg" alt="描述"> </body> </html>
1.2 常见标签
<html>
:文档根元素。<head>
:包含文档的元数据,如标题、样式表链接等。<title>
:文档的标题。<body>
:文档的主体内容。<h1>
到<h6>
:标题标签,<h1>
是最大的标题,<h6>
是最小的标题。<p>
:段落标签。<a>
:超链接标签,href
属性指定链接的目标。<img>
:图像标签,src
属性指定图像的URL,alt
属性提供替代文本。<div>
:块级容器,用于分组和布局。<span>
:内联容器,用于文本格式化。2. CSS (Cascading Style Sheets)
2.1 基本概念
CSS 用于控制网页的样式和布局。通过CSS,可以改变字体、颜色、间距、边框等。
2.2 选择器
选择器用于选择要应用样式的HTML元素。常见的选择器包括:
标签选择器:选择特定的HTML标签。
p { color: blue; }
类选择器:选择具有特定类名的元素。
.highlight { background-color: yellow; }
ID选择器:选择具有特定ID的元素。
#header { font-size: 24px; }
属性选择器:选择具有特定属性的元素。
a[target="_blank"] { color: green; }
伪类选择器:选择具有特定状态的元素。
a:hover { text-decoration: underline; }
组合选择器:组合多个选择器以选择更具体的元素。
div p { color: red; }
3. 在爬虫中的应用
3.1 解析HTML
使用Python库如
BeautifulSoup
或lxml
来解析HTML文档并提取所需数据。示例:使用BeautifulSoup解析HTML
from bs4 import BeautifulSoup import requests # 发送HTTP请求获取网页内容 url = 'https://example.com' response = requests.get(url) html_content = response.text # 使用BeautifulSoup解析HTML soup = BeautifulSoup(html_content, 'html.parser') # 提取标题 title = soup.title.string print(f"标题: {title}") # 提取所有段落 paragraphs = soup.find_all('p') for p in paragraphs: print(p.text) # 提取带有特定类名的元素 highlighted_elements = soup.find_all(class_='highlight') for element in highlighted_elements: print(element.text) # 提取带有特定ID的元素 header_element = soup.find(id='header') print(header_element.text) # 提取带有特定属性的元素 external_links = soup.find_all('a', target='_blank') for link in external_links: print(link['href'])
3.2 使用CSS选择器
BeautifulSoup
和lxml
都支持使用CSS选择器来定位元素。示例:使用CSS选择器
from bs4 import BeautifulSoup import requests # 发送HTTP请求获取网页内容 url = 'https://example.com' response = requests.get(url) html_content = response.text # 使用BeautifulSoup解析HTML soup = BeautifulSoup(html_content, 'html.parser') # 使用CSS选择器提取标题 title = soup.select_one('title').string print(f"标题: {title}") # 提取所有段落 paragraphs = soup.select('p') for p in paragraphs: print(p.text) # 提取带有特定类名的元素 highlighted_elements = soup.select('.highlight') for element in highlighted_elements: print(element.text) # 提取带有特定ID的元素 header_element = soup.select_one('#header') print(header_element.text) # 提取带有特定属性的元素 external_links = soup.select('a[target="_blank"]') for link in external_links: print(link['href'])
Python库
1、python官网:PyPI · The Python Package Index
2、知乎对python的库的讲解:https://zhuanlan.zhihu.com/p/89477028
Requests库:用于发送网络请求,获取网页内容。
1. 安装
requests
库首先,你需要安装
requests
库。可以通过pip
命令来安装:pip install requests
2. 发送 GET 请求
发送 GET 请求是最常见的操作之一,用于从服务器获取数据。
基本用法
import requests # 发送GET请求 response = requests.get('https://api.example.com/data') # 检查请求是否成功 if response.status_code == 200: # 打印响应内容 print(response.text) else: print(f"请求失败,状态码: {response.status_code}")
带参数的 GET 请求
你可以在 URL 后面附加查询参数,或者使用
params
参数传递字典。import requests # 定义查询参数 params = { 'key1': 'value1', 'key2': 'value2' } # 发送GET请求 response = requests.get('https://api.example.com/data', params=params) # 检查请求是否成功 if response.status_code == 200: # 打印响应内容 print(response.text) else: print(f"请求失败,状态码: {response.status_code}")
3. 发送 POST 请求
发送 POST 请求通常用于向服务器提交数据,例如表单数据或文件上传。
基本用法
import requests # 定义请求体数据 data = { 'username': 'user123', 'password': 'pass456' } # 发送POST请求 response = requests.post('https://api.example.com/login', data=data) # 检查请求是否成功 if response.status_code == 200: # 打印响应内容 print(response.text) else: print(f"请求失败,状态码: {response.status_code}")
发送 JSON 数据
如果需要发送 JSON 格式的数据,可以使用
json
参数。import requests # 定义请求体数据 data = { 'username': 'user123', 'password': 'pass456' } # 发送POST请求 response = requests.post('https://api.example.com/login', json=data) # 检查请求是否成功 if response.status_code == 200: # 打印响应内容 print(response.text) else: print(f"请求失败,状态码: {response.status_code}")
4. 处理响应
requests
库提供了多种方法来处理响应,包括获取响应状态码、响应头和响应体。获取状态码
import requests response = requests.get('https://api.example.com/data') status_code = response.status_code print(f"状态码: {status_code}")
获取响应头
import requests response = requests.get('https://api.example.com/data') headers = response.headers print(f"响应头: {headers}")
获取响应体
import requests response = requests.get('https://api.example.com/data') text = response.text # 获取响应内容的文本形式 json_data = response.json() # 如果响应内容是JSON格式 print(f"响应内容: {text}") print(f"JSON数据: {json_data}")
5. 高级用法
设置请求头
有时候需要设置请求头,例如设置
User-Agent
或Content-Type
。import requests headers = { 'User-Agent': 'MyApp/1.0', 'Content-Type': 'application/json' } response = requests.get('https://api.example.com/data', headers=headers) print(response.text)
设置超时
可以通过
timeout
参数设置请求的超时时间(单位为秒)。import requests response = requests.get('https://api.example.com/data', timeout=5) print(response.text)
处理 cookies
可以使用
cookies
参数发送 cookies,或者从响应中获取 cookies。import requests # 发送带有cookies的请求 cookies = {'session_id': '12345'} response = requests.get('https://api.example.com/data', cookies=cookies) print(response.text) # 从响应中获取cookies cookies = response.cookies print(cookies)
会话对象
使用
Session
对象可以保持会话状态,例如保持 cookies。import requests # 创建一个Session对象 session = requests.Session() # 发送第一个请求 response1 = session.get('https://api.example.com/login', data={'username': 'user123', 'password': 'pass456'}) print(response1.text) # 发送第二个请求,会话状态保持 response2 = session.get('https://api.example.com/dashboard') print(response2.text)
BeautifulSoup库:解析HTML文档,提取所需信息。
1. 安装
BeautifulSoup
库首先,你需要安装
BeautifulSoup
库。可以通过pip
命令来安装:pip install beautifulsoup4
2. 基本用法
2.1 创建
BeautifulSoup
对象首先,你需要从
bs4
模块中导入BeautifulSoup
类,并创建一个BeautifulSoup
对象。from bs4 import BeautifulSoup import requests # 发送HTTP请求获取网页内容 url = 'https://example.com' response = requests.get(url) html_content = response.text # 创建BeautifulSoup对象 soup = BeautifulSoup(html_content, 'html.parser')
3. 解析 HTML 文档
3.1 提取标题
# 提取标题 title = soup.title.string print(f"标题: {title}")
3.2 提取所有段落
# 提取所有段落 paragraphs = soup.find_all('p') for p in paragraphs: print(p.text)
3.3 提取带有特定类名的元素
# 提取带有特定类名的元素 highlighted_elements = soup.find_all(class_='highlight') for element in highlighted_elements: print(element.text)
3.4 提取带有特定 ID 的元素
# 提取带有特定ID的元素 header_element = soup.find(id='header') print(header_element.text)
3.5 提取带有特定属性的元素
# 提取带有特定属性的元素 external_links = soup.find_all('a', target='_blank') for link in external_links: print(link['href'])
4. 使用 CSS 选择器
BeautifulSoup
支持使用 CSS 选择器来定位元素,这使得提取信息更加灵活和方便。4.1 提取标题
# 提取标题 title = soup.select_one('title').string print(f"标题: {title}")
4.2 提取所有段落
# 提取所有段落 paragraphs = soup.select('p') for p in paragraphs: print(p.text)
4.3 提取带有特定类名的元素
# 提取带有特定类名的元素 highlighted_elements = soup.select('.highlight') for element in highlighted_elements: print(element.text)
4.4 提取带有特定 ID 的元素
# 提取带有特定ID的元素 header_element = soup.select_one('#header') print(header_element.text)
4.5 提取带有特定属性的元素
# 提取带有特定属性的元素 external_links = soup.select('a[target="_blank"]') for link in external_links: print(link['href'])
5. 处理嵌套结构
有时需要处理嵌套的 HTML 结构,
BeautifulSoup
提供了多种方法来遍历和处理这些结构。5.1 遍历子节点
# 遍历子节点 for child in header_element.children: print(child)
5.2 遍历兄弟节点
# 遍历兄弟节点 for sibling in header_element.next_siblings: print(sibling)
6. 处理特殊字符
HTML 文档中可能会包含特殊字符,
BeautifulSoup
会自动处理这些字符。# 提取包含特殊字符的文本 special_text = soup.find('p', class_='special').text print(special_text)
7. 处理注释
HTML 文档中可能会包含注释,
BeautifulSoup
也提供了处理注释的方法。# 提取注释 for comment in soup.find_all(string=lambda text: isinstance(text, Comment)): print(comment)
lxml库:提供快速的XML和HTML处理功能,也可以用于解析网页。
1. 安装
lxml
库首先,你需要安装
lxml
库。可以通过pip
命令来安装:pip install lxml
2. 基本用法
2.1 创建
ElementTree
对象
lxml
使用ElementTree
API 来解析和操作 XML 和 HTML 文档。首先,你需要从lxml.etree
模块中导入相关类,并创建一个ElementTree
对象。from lxml import etree import requests # 发送HTTP请求获取网页内容 url = 'https://example.com' response = requests.get(url) html_content = response.text # 解析HTML文档 tree = etree.HTML(html_content)
3. 解析 HTML 文档
3.1 提取标题
# 提取标题 title = tree.xpath('//title/text()')[0] print(f"标题: {title}")
3.2 提取所有段落
# 提取所有段落 paragraphs = tree.xpath('//p/text()') for p in paragraphs: print(p)
3.3 提取带有特定类名的元素
# 提取带有特定类名的元素 highlighted_elements = tree.xpath('//p[@class="highlight"]/text()') for element in highlighted_elements: print(element)
3.4 提取带有特定 ID 的元素
# 提取带有特定ID的元素 header_element = tree.xpath('//div[@id="header"]/text()')[0] print(header_element)
3.5 提取带有特定属性的元素
# 提取带有特定属性的元素 external_links = tree.xpath('//a[@target="_blank"]/@href') for link in external_links: print(link)
4. 使用 XPath 表达式
XPath 是一种在 XML 文档中查找信息的语言,
lxml
支持使用 XPath 表达式来定位和提取元素。4.1 提取多级嵌套的元素
# 提取多级嵌套的元素 nested_elements = tree.xpath('//div[@class="container"]/p[@class="highlight"]/text()') for element in nested_elements: print(element)
4.2 提取包含特定文本的元素
# 提取包含特定文本的元素 elements_with_text = tree.xpath('//p[contains(text(), "特定文本")]/text()') for element in elements_with_text: print(element)
5. 处理特殊字符
HTML 文档中可能会包含特殊字符,
lxml
会自动处理这些字符。# 提取包含特殊字符的文本 special_text = tree.xpath('//p[@class="special"]/text()')[0] print(special_text)
6. 处理注释
HTML 文档中可能会包含注释,
lxml
也提供了处理注释的方法。# 提取注释 comments = tree.xpath('//comment()') for comment in comments: print(comment)
7. 处理命名空间
在处理包含命名空间的 XML 文档时,需要特别注意命名空间的处理。
# 解析包含命名空间的XML文档 xml_content = ''' <root xmlns:ns="http://example.com/ns"> <ns:item id="1">Item 1</ns:item> <ns:item id="2">Item 2</ns:item> </root> ''' # 解析XML文档 tree = etree.fromstring(xml_content) # 提取命名空间下的元素 items = tree.xpath('//ns:item/text()', namespaces={'ns': 'http://example.com/ns'}) for item in items: print(item)
8. 处理 HTML 错误
lxml
可以处理不标准的 HTML 文档,自动修复一些常见的错误。# 解析不标准的HTML文档 html_content = '<html><body><p>未闭合的标签</p>' tree = etree.HTML(html_content) # 提取段落 paragraphs = tree.xpath('//p/text()') for p in paragraphs: print(p)
Scrapy框架:一个强大的爬虫框架,适用于大规模的数据抓取项目。
1. 安装
Scrapy
框架首先,你需要安装
Scrapy
框架。可以通过pip
命令来安装pip install scrapy
2. 创建 Scrapy 项目
使用
scrapy startproject
命令创建一个新的 Scrapy 项目。scrapy startproject myproject
这将创建一个名为
myproject
的目录,包含以下文件和目录结构:myproject/ scrapy.cfg # 部署配置文件 myproject/ # Python 包 __init__.py # 初始化文件 items.py # 定义数据项 middlewares.py # 中间件 pipelines.py # 数据管道 settings.py # 项目设置 spiders/ # 爬虫文件夹 __init__.py spider1.py # 爬虫文件
3. 编写爬虫
3.1 创建爬虫
在
spiders
目录下创建一个新的爬虫文件,例如spider1.py
。import scrapy class MySpider(scrapy.Spider): name = 'myspider' # 爬虫名称 allowed_domains = ['example.com'] # 允许的域名 start_urls = ['https://example.com'] # 起始URL def parse(self, response): # 解析响应内容 title = response.xpath('//title/text()').get() print(f"标题: {title}") # 提取所有段落 paragraphs = response.xpath('//p/text()').getall() for p in paragraphs: print(p) # 继续请求其他页面 next_page = response.xpath('//a[@class="next"]/@href').get() if next_page: yield response.follow(next_page, self.parse)
3.2 运行爬虫
在项目根目录下运行爬虫:
scrapy crawl myspider
4. 定义数据项
在
items.py
文件中定义数据项,用于存储抓取的数据。import scrapy class MyItem(scrapy.Item): title = scrapy.Field() content = scrapy.Field() url = scrapy.Field()
5. 数据提取
在爬虫中使用 XPath 或 CSS 选择器提取数据,并将数据存储到定义的数据项中。
import scrapy from myproject.items import MyItem class MySpider(scrapy.Spider): name = 'myspider' allowed_domains = ['example.com'] start_urls = ['https://example.com'] def parse(self, response): # 解析响应内容 item = MyItem() item['title'] = response.xpath('//title/text()').get() item['content'] = response.xpath('//p/text()').getall() item['url'] = response.url yield item # 继续请求其他页面 next_page = response.xpath('//a[@class="next"]/@href').get() if next_page: yield response.follow(next_page, self.parse)
6. 数据存储
在
pipelines.py
文件中定义数据管道,处理抓取的数据并存储到文件、数据库等。import json class JsonWriterPipeline: def open_spider(self, spider): self.file = open('items.json', 'w') def close_spider(self, spider): self.file.close() def process_item(self, item, spider): line = json.dumps(dict(item)) + "\n" self.file.write(line) return item
在
settings.py
文件中启用数据管道:ITEM_PIPELINES = { 'myproject.pipelines.JsonWriterPipeline': 300, }
7. 中间件
中间件用于处理请求和响应,例如设置用户代理、处理重试等。
class MyMiddleware: def process_request(self, request, spider): request.headers['User-Agent'] = 'MyApp/1.0' def process_response(self, request, response, spider): if response.status == 404: print(f"404 Not Found: {request.url}") return response
在
settings.py
文件中启用中间件:DOWNLOADER_MIDDLEWARES = { 'myproject.middlewares.MyMiddleware': 543, }
8. 配置设置
在
settings.py
文件中配置项目的各种设置,例如请求延迟、并发请求等。# 请求延迟 DOWNLOAD_DELAY = 1 # 并发请求 CONCURRENT_REQUESTS = 16 # 用户代理 USER_AGENT = 'MyApp/1.0' # 禁用 cookies COOKIES_ENABLED = False # 重试设置 RETRY_ENABLED = True RETRY_TIMES = 3
9. 部署和运行
9.1 本地运行
在本地开发环境中运行爬虫:
scrapy crawl myspider
9.2 部署到 Scrapy Cloud
Scrapy Cloud 是一个托管服务,可以方便地部署和管理 Scrapy 项目。
- 注册并登录 Scrapy Cloud。
- 创建一个新的项目。
- 将本地项目推送到 Scrapy Cloud。
scrapyc deploy
Selenium库:当需要与JavaScript动态加载的内容交互时使用,可以模拟浏览器行为。
1. 安装
Selenium
库首先,你需要安装
Selenium
库。可以通过pip
命令来安装:pip install selenium
此外,还需要下载浏览器驱动程序(如 ChromeDriver),并将其路径添加到系统的环境变量中。你可以从 ChromeDriver 下载页面 下载适合你浏览器版本的驱动程序。
2. 基本用法
2.1 创建 WebDriver 对象
首先,需要从
selenium.webdriver
模块中导入相关类,并创建一个WebDriver
对象。from selenium import webdriver # 创建 WebDriver 对象 driver = webdriver.Chrome() # 使用 Chrome 浏览器
2.2 打开网页
使用
get
方法打开指定的网页。driver.get('https://example.com')
2.3 关闭浏览器
完成操作后,使用
quit
方法关闭浏览器。driver.quit()
3. 常见操作
3.1 查找元素
使用
find_element_by_*
方法查找单个元素,或使用find_elements_by_*
方法查找多个元素。# 查找单个元素 element = driver.find_element_by_id('element_id') element = driver.find_element_by_name('element_name') element = driver.find_element_by_class_name('element_class') element = driver.find_element_by_tag_name('tag_name') element = driver.find_element_by_link_text('link_text') element = driver.find_element_by_partial_link_text('partial_link_text') element = driver.find_element_by_xpath('//xpath_expression') element = driver.find_element_by_css_selector('css_selector') # 查找多个元素 elements = driver.find_elements_by_class_name('element_class')
3.2 操作元素
可以对找到的元素进行各种操作,如点击、输入文本等。
# 点击按钮 button = driver.find_element_by_id('submit_button') button.click() # 输入文本 input_field = driver.find_element_by_id('input_field') input_field.send_keys('Hello, World!') # 清空输入框 input_field.clear()
3.3 获取元素属性
可以获取元素的属性值。
# 获取元素的属性值 attribute_value = element.get_attribute('attribute_name') print(attribute_value)
3.4 获取页面内容
可以获取页面的 HTML 内容。
# 获取页面的 HTML 内容 html_content = driver.page_source print(html_content)
4. 处理动态内容
4.1 显式等待
使用
WebDriverWait
和expected_conditions
处理动态内容,等待某个条件满足后再进行操作。from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 显式等待,直到某个元素可见 element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, 'element_id')) ) # 显式等待,直到某个元素可点击 element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, 'submit_button')) )
4.2 隐式等待
设置隐式等待时间,如果在指定时间内找不到元素,则抛出
NoSuchElementException
异常。# 设置隐式等待时间为 10 秒 driver.implicitly_wait(10)
5. 高级用法
5.1 处理弹出窗口
可以处理浏览器的弹出窗口,如确认对话框、警告对话框等。
# 处理确认对话框 alert = driver.switch_to.alert alert.accept() # 点击“确定” alert.dismiss() # 点击“取消” # 获取警告对话框的文本 alert_text = alert.text print(alert_text)
5.2 处理多窗口
可以处理多个窗口或标签页。
# 获取当前窗口句柄 current_window = driver.current_window_handle # 获取所有窗口句柄 all_windows = driver.window_handles # 切换到新的窗口 driver.switch_to.window(all_windows[1]) # 切换回原来的窗口 driver.switch_to.window(current_window)
5.3 处理表单
可以处理表单的提交。
# 填写表单 username_field = driver.find_element_by_id('username') password_field = driver.find_element_by_id('password') submit_button = driver.find_element_by_id('submit_button') username_field.send_keys('user123') password_field.send_keys('pass456') submit_button.click()
6. 示例:登录网站
下面是一个完整的示例,演示如何使用
Selenium
登录一个网站。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 # 创建 WebDriver 对象 driver = webdriver.Chrome() # 打开登录页面 driver.get('https://example.com/login') # 等待用户名输入框出现 username_field = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, 'username')) ) # 等待密码输入框出现 password_field = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, 'password')) ) # 等待提交按钮出现 submit_button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, 'submit_button')) ) # 填写表单 username_field.send_keys('user123') password_field.send_keys('pass456') # 提交表单 submit_button.click() # 等待登录成功后的页面元素出现 success_message = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, 'success_message')) ) # 打印成功消息 print(success_message.text) # 关闭浏览器 driver.quit()
数据存储
文件操作:学会将爬取的数据保存到本地文件中,如CSV、JSON等格式。
1. 保存为 CSV 文件
1.1 使用
csv
模块Python 的标准库中有一个
csv
模块,可以方便地处理 CSV 文件。import csv # 示例数据 data = [ ['Name', 'Age', 'City'], ['Alice', 25, 'New York'], ['Bob', 30, 'Los Angeles'], ['Charlie', 35, 'Chicago'] ] # 写入 CSV 文件 with open('output.csv', 'w', newline='') as csvfile: writer = csv.writer(csvfile) writer.writerows(data) # 读取 CSV 文件 with open('output.csv', 'r') as csvfile: reader = csv.reader(csvfile) for row in reader: print(row)
1.2 使用
pandas
库
pandas
是一个强大的数据处理库,可以方便地处理和保存数据。import pandas as pd # 示例数据 data = { 'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35], 'City': ['New York', 'Los Angeles', 'Chicago'] } # 创建 DataFrame df = pd.DataFrame(data) # 保存为 CSV 文件 df.to_csv('output.csv', index=False) # 读取 CSV 文件 df = pd.read_csv('output.csv') print(df)
2. 保存为 JSON 文件
2.1 使用
json
模块Python 的标准库中有一个
json
模块,可以方便地处理 JSON 数据。import json # 示例数据 data = [ {'Name': 'Alice', 'Age': 25, 'City': 'New York'}, {'Name': 'Bob', 'Age': 30, 'City': 'Los Angeles'}, {'Name': 'Charlie', 'Age': 35, 'City': 'Chicago'} ] # 写入 JSON 文件 with open('output.json', 'w') as jsonfile: json.dump(data, jsonfile, indent=4) # 读取 JSON 文件 with open('output.json', 'r') as jsonfile: data = json.load(jsonfile) print(data)
3. 结合 Scrapy 保存数据
在 Scrapy 项目中,可以使用数据管道 (
pipelines
) 将数据保存到文件中。3.1 保存为 CSV 文件
在
pipelines.py
文件中定义一个数据管道,将数据保存为 CSV 文件。import csv class CsvPipeline: def open_spider(self, spider): self.file = open('output.csv', 'w', newline='') self.writer = csv.writer(self.file) self.writer.writerow(['Name', 'Age', 'City']) def close_spider(self, spider): self.file.close() def process_item(self, item, spider): self.writer.writerow([item['name'], item['age'], item['city']]) return item
在
settings.py
文件中启用数据管道:ITEM_PIPELINES = { 'myproject.pipelines.CsvPipeline': 300, }
3.2 保存为 JSON 文件
在
pipelines.py
文件中定义一个数据管道,将数据保存为 JSON 文件。import json class JsonPipeline: def open_spider(self, spider): self.file = open('output.json', 'w') def close_spider(self, spider): self.file.close() def process_item(self, item, spider): line = json.dumps(dict(item)) + "\n" self.file.write(line) return item
在
settings.py
文件中启用数据管道:ITEM_PIPELINES = { 'myproject.pipelines.JsonPipeline': 300, }
4. 结合 Selenium 保存数据
在使用 Selenium 抓取数据时,可以将数据保存到文件中。
from selenium import webdriver import json # 创建 WebDriver 对象 driver = webdriver.Chrome() # 打开网页 driver.get('https://example.com') # 提取数据 data = [] elements = driver.find_elements_by_css_selector('.item') for element in elements: name = element.find_element_by_css_selector('.name').text age = int(element.find_element_by_css_selector('.age').text) city = element.find_element_by_css_selector('.city').text data.append({'Name': name, 'Age': age, 'City': city}) # 保存为 JSON 文件 with open('output.json', 'w') as jsonfile: json.dump(data, jsonfile, indent=4) # 关闭浏览器 driver.quit()
数据库操作:了解如何使用SQLite、MySQL或MongoDB等数据库存储数据。
1. 使用 SQLite
SQLite 是一个轻量级的数据库引擎,非常适合小型项目和测试。
1.1 安装
sqlite3
模块Python 标准库中已经包含了
sqlite3
模块,无需额外安装。1.2 创建和连接数据库
import sqlite3 # 连接到 SQLite 数据库(如果不存在则创建) conn = sqlite3.connect('example.db') # 创建游标对象 cursor = conn.cursor() # 创建表 cursor.execute(''' CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, city TEXT ) ''') # 提交事务 conn.commit()
1.3 插入数据
# 插入数据 cursor.execute('INSERT INTO users (name, age, city) VALUES (?, ?, ?)', ('Alice', 25, 'New York')) cursor.execute('INSERT INTO users (name, age, city) VALUES (?, ?, ?)', ('Bob', 30, 'Los Angeles')) # 提交事务 conn.commit()
1.4 查询数据
# 查询数据 cursor.execute('SELECT * FROM users') rows = cursor.fetchall() for row in rows: print(row)
1.5 关闭连接
# 关闭连接 conn.close()
2. 使用 MySQL
MySQL 是一个广泛使用的开源关系型数据库管理系统。
2.1 安装
mysql-connector-python
库pip install mysql-connector-python
2.2 创建和连接数据库
import mysql.connector # 连接到 MySQL 数据库 conn = mysql.connector.connect( host='localhost', user='your_username', password='your_password', database='your_database' ) # 创建游标对象 cursor = conn.cursor() # 创建表 cursor.execute(''' CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), age INT, city VARCHAR(100) ) ''') # 提交事务 conn.commit()
2.3 插入数据
# 插入数据 cursor.execute('INSERT INTO users (name, age, city) VALUES (%s, %s, %s)', ('Alice', 25, 'New York')) cursor.execute('INSERT INTO users (name, age, city) VALUES (%s, %s, %s)', ('Bob', 30, 'Los Angeles')) # 提交事务 conn.commit()
2.4 查询数据
# 查询数据 cursor.execute('SELECT * FROM users') rows = cursor.fetchall() for row in rows: print(row)
2.5 关闭连接
# 关闭连接 conn.close()
3. 使用 MongoDB
MongoDB 是一个流行的 NoSQL 数据库,适用于处理大量非结构化数据。
3.1 安装
pymongo
库pip install pymongo
3.2 创建和连接数据库
from pymongo import MongoClient # 连接到 MongoDB client = MongoClient('mongodb://localhost:27017/') # 选择数据库 db = client['your_database'] # 选择集合 collection = db['users'] # 插入数据 data = [ {'name': 'Alice', 'age': 25, 'city': 'New York'}, {'name': 'Bob', 'age': 30, 'city': 'Los Angeles'} ] # 插入多条数据 result = collection.insert_many(data) # 打印插入的文档 ID print(result.inserted_ids)
3.3 查询数据
# 查询数据 documents = collection.find() for doc in documents: print(doc)
3.4 更新数据
# 更新数据 result = collection.update_one({'name': 'Alice'}, {'$set': {'age': 26}}) print(f"匹配到的文档数: {result.matched_count}, 修改的文档数: {result.modified_count}")
3.5 删除数据
# 删除数据 result = collection.delete_one({'name': 'Bob'}) print(f"删除的文档数: {result.deleted_count}")
4. 结合 Scrapy 存储数据
在 Scrapy 项目中,可以使用数据管道 (
pipelines
) 将数据存储到数据库中。4.1 使用 SQLite
在
pipelines.py
文件中定义一个数据管道,将数据存储到 SQLite 数据库中。import sqlite3 class SQLitePipeline: def open_spider(self, spider): self.conn = sqlite3.connect('example.db') self.cursor = self.conn.cursor() self.cursor.execute(''' CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, city TEXT ) ''') self.conn.commit() def close_spider(self, spider): self.conn.close() def process_item(self, item, spider): self.cursor.execute('INSERT INTO users (name, age, city) VALUES (?, ?, ?)', (item['name'], item['age'], item['city'])) self.conn.commit() return item
在
settings.py
文件中启用数据管道:ITEM_PIPELINES = { 'myproject.pipelines.SQLitePipeline': 300, }
4.2 使用 MySQL
在
pipelines.py
文件中定义一个数据管道,将数据存储到 MySQL 数据库中。import mysql.connector class MySQLPipeline: def open_spider(self, spider): self.conn = mysql.connector.connect( host='localhost', user='your_username', password='your_password', database='your_database' ) self.cursor = self.conn.cursor() self.cursor.execute(''' CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), age INT, city VARCHAR(100) ) ''') self.conn.commit() def close_spider(self, spider): self.conn.close() def process_item(self, item, spider): self.cursor.execute('INSERT INTO users (name, age, city) VALUES (%s, %s, %s)', (item['name'], item['age'], item['city'])) self.conn.commit() return item
在
settings.py
文件中启用数据管道:ITEM_PIPELINES = { 'myproject.pipelines.MySQLPipeline': 300, }
4.3 使用 MongoDB
在
pipelines.py
文件中定义一个数据管道,将数据存储到 MongoDB 数据库中。from pymongo import MongoClient class MongoDBPipeline: def open_spider(self, spider): self.client = MongoClient('mongodb://localhost:27017/') self.db = self.client['your_database'] self.collection = self.db['users'] def close_spider(self, spider): self.client.close() def process_item(self, item, spider): self.collection.insert_one(dict(item)) return item
在
settings.py
文件中启用数据管道:ITEM_PIPELINES = { 'myproject.pipelines.MongoDBPipeline': 300, }
进阶技术
数据清洗:使用Pandas等库对爬取的数据进行预处理,去除无效或错误的数据。
1. 安装
pandas
库首先,确保你已经安装了
pandas
库。可以通过pip
命令来安装:pip install pandas
2. 基本用法
2.1 导入库
import pandas as pd
2.2 读取数据
可以从多种来源读取数据,例如 CSV 文件、Excel 文件、SQL 数据库等。
# 从 CSV 文件读取数据 df = pd.read_csv('data.csv') # 从 Excel 文件读取数据 df = pd.read_excel('data.xlsx') # 从 SQL 数据库读取数据 import sqlite3 conn = sqlite3.connect('database.db') df = pd.read_sql_query('SELECT * FROM table_name', conn)
3. 常见的数据清洗任务
3.1 查看数据
查看数据的基本信息,包括前几行、列名、数据类型等。
# 查看前几行 print(df.head()) # 查看列名 print(df.columns) # 查看数据类型 print(df.dtypes) # 查看数据统计信息 print(df.describe())
3.2 处理缺失值
处理缺失值是数据清洗中常见的任务之一。
# 检查缺失值 print(df.isnull().sum()) # 删除含有缺失值的行 df.dropna(inplace=True) # 填充缺失值 df.fillna(value=0, inplace=True) # 用0填充 df.fillna(method='ffill', inplace=True) # 前向填充 df.fillna(method='bfill', inplace=True) # 后向填充
3.3 处理重复值
删除重复的行。
# 检查重复值 print(df.duplicated().sum()) # 删除重复行 df.drop_duplicates(inplace=True)
3.4 转换数据类型
将某些列的数据类型转换为其他类型。
# 转换数据类型 df['age'] = df['age'].astype(int) df['salary'] = df['salary'].astype(float)
3.5 重命名列
重命名列名。
# 重命名列 df.rename(columns={'old_name': 'new_name'}, inplace=True)
3.6 处理异常值
检测和处理异常值。
# 检测异常值 q1 = df['age'].quantile(0.25) q3 = df['age'].quantile(0.75) iqr = q3 - q1 lower_bound = q1 - 1.5 * iqr upper_bound = q3 + 1.5 * iqr # 删除异常值 df = df[(df['age'] >= lower_bound) & (df['age'] <= upper_bound)]
3.7 字符串处理
处理字符串数据,例如去除空格、替换字符串等。
# 去除空格 df['name'] = df['name'].str.strip() # 替换字符串 df['city'] = df['city'].str.replace('New York', 'NYC')
3.8 日期处理
处理日期数据,例如将字符串转换为日期格式。
# 转换日期格式 df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')
4. 示例:综合数据清洗
下面是一个综合示例,展示如何使用
pandas
进行数据清洗。import pandas as pd # 从 CSV 文件读取数据 df = pd.read_csv('data.csv') # 查看数据基本信息 print(df.head()) print(df.dtypes) # 处理缺失值 print(df.isnull().sum()) df.dropna(subset=['name'], inplace=True) # 删除 name 列有缺失值的行 df.fillna({'age': 0, 'salary': 0}, inplace=True) # 用0填充 age 和 salary 列的缺失值 # 处理重复值 print(df.duplicated().sum()) df.drop_duplicates(inplace=True) # 转换数据类型 df['age'] = df['age'].astype(int) df['salary'] = df['salary'].astype(float) # 重命名列 df.rename(columns={'old_name': 'new_name'}, inplace=True) # 处理异常值 q1 = df['age'].quantile(0.25) q3 = df['age'].quantile(0.75) iqr = q3 - q1 lower_bound = q1 - 1.5 * iqr upper_bound = q3 + 1.5 * iqr df = df[(df['age'] >= lower_bound) & (df['age'] <= upper_bound)] # 字符串处理 df['name'] = df['name'].str.strip() df['city'] = df['city'].str.replace('New York', 'NYC') # 日期处理 df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d') # 查看清洗后的数据 print(df.head())
5. 保存清洗后的数据
将清洗后的数据保存到文件中,例如 CSV 文件或 Excel 文件。
# 保存到 CSV 文件 df.to_csv('cleaned_data.csv', index=False) # 保存到 Excel 文件 df.to_excel('cleaned_data.xlsx', index=False)
异步编程:利用asyncio和aiohttp等库提高爬虫效率,实现并发请求。
1. 安装
aiohttp
库首先,确保你已经安装了
aiohttp
库。可以通过pip
命令来安装:pip install aiohttp
2. 基本用法
2.1 导入库
import asyncio import aiohttp
2.2 创建异步函数
使用
async def
定义异步函数。async def fetch(session, url): async with session.get(url) as response: return await response.text()
2.3 创建主函数
使用
asyncio.run
运行异步主函数。async def main(): urls = [ 'https://example.com', 'https://example.org', 'https://example.net' ] async with aiohttp.ClientSession() as session: tasks = [fetch(session, url) for url in urls] results = await asyncio.gather(*tasks) for result in results: print(result) # 运行主函数 asyncio.run(main())
3. 处理请求结果
3.1 解析 HTML 内容
可以使用
BeautifulSoup
或lxml
解析返回的 HTML 内容。from bs4 import BeautifulSoup async def fetch_and_parse(session, url): async with session.get(url) as response: html_content = await response.text() soup = BeautifulSoup(html_content, 'html.parser') title = soup.title.string return title async def main(): urls = [ 'https://example.com', 'https://example.org', 'https://example.net' ] async with aiohttp.ClientSession() as session: tasks = [fetch_and_parse(session, url) for url in urls] results = await asyncio.gather(*tasks) for result in results: print(result) # 运行主函数 asyncio.run(main())
4. 限制并发请求数量
为了防止过多的并发请求导致服务器压力过大,可以使用
asyncio.Semaphore
限制并发请求数量。import asyncio import aiohttp from bs4 import BeautifulSoup semaphore = asyncio.Semaphore(10) # 限制并发请求数量为10 async def fetch_and_parse(session, url): async with semaphore: async with session.get(url) as response: html_content = await response.text() soup = BeautifulSoup(html_content, 'html.parser') title = soup.title.string return title async def main(): urls = [ 'https://example.com', 'https://example.org', 'https://example.net' ] async with aiohttp.ClientSession() as session: tasks = [fetch_and_parse(session, url) for url in urls] results = await asyncio.gather(*tasks) for result in results: print(result) # 运行主函数 asyncio.run(main())
5. 错误处理
在异步编程中,错误处理非常重要。可以使用
try-except
块来捕获和处理异常。import asyncio import aiohttp from bs4 import BeautifulSoup semaphore = asyncio.Semaphore(10) # 限制并发请求数量为10 async def fetch_and_parse(session, url): try: async with semaphore: async with session.get(url) as response: html_content = await response.text() soup = BeautifulSoup(html_content, 'html.parser') title = soup.title.string return title except Exception as e: print(f"Error fetching {url}: {e}") return None async def main(): urls = [ 'https://example.com', 'https://example.org', 'https://example.net' ] async with aiohttp.ClientSession() as session: tasks = [fetch_and_parse(session, url) for url in urls] results = await asyncio.gather(*tasks) for result in results: if result is not None: print(result) # 运行主函数 asyncio.run(main())
6. 结合 Scrapy 使用异步请求
虽然 Scrapy 本身是同步的,但可以通过
scrapy-asyncio
扩展来实现异步请求。6.1 安装
scrapy-asyncio
pip install scrapy-asyncio
6.2 配置 Scrapy 项目
在
settings.py
文件中启用scrapy-asyncio
。ASYNCIO_EVENT_LOOP = 'uvloop'
6.3 创建异步爬虫
在
spiders
目录下创建一个新的异步爬虫文件,例如async_spider.py
。import scrapy from scrapy.spiders import AsyncSpider from scrapy.http import Request from bs4 import BeautifulSoup class AsyncSpiderExample(AsyncSpider): name = 'async_spider' allowed_domains = ['example.com'] start_urls = ['https://example.com'] async def parse(self, response): soup = BeautifulSoup(response.text, 'html.parser') title = soup.title.string print(f"Title: {title}") # 提取更多链接 links = soup.find_all('a') for link in links: href = link.get('href') if href: yield Request(href, callback=self.parse)
代理和用户代理设置:为了避免被目标网站封禁IP,学习如何设置代理服务器和随机更换User-Agent。
1. 设置代理服务器
1.1 使用
requests
库
requests
库支持通过proxies
参数设置代理服务器。import requests # 设置代理 proxies = { 'http': 'http://123.45.67.89:8080', 'https': 'https://123.45.67.89:8080' } # 发送请求 response = requests.get('https://example.com', proxies=proxies) # 打印响应内容 print(response.text)
1.2 使用
aiohttp
库
aiohttp
库也支持通过ProxyConnector
设置代理服务器。import aiohttp import asyncio async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): # 设置代理 connector = aiohttp.TCPConnector(force_close=True) proxy = 'http://123.45.67.89:8080' async with aiohttp.ClientSession(connector=connector) as session: response = await fetch(session, 'https://example.com', proxy=proxy) print(response) # 运行主函数 asyncio.run(main())
2. 随机更换 User-Agent
2.1 使用
requests
库可以使用
headers
参数设置 User-Agent,并通过随机选择 User-Agent 来避免被封禁。import requests import random # 定义 User-Agent 列表 user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' ] # 随机选择一个 User-Agent headers = {'User-Agent': random.choice(user_agents)} # 发送请求 response = requests.get('https://example.com', headers=headers) # 打印响应内容 print(response.text)
2.2 使用
aiohttp
库在
aiohttp
中也可以通过headers
参数设置 User-Agent。import aiohttp import asyncio import random # 定义 User-Agent 列表 user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' ] async def fetch(session, url): # 随机选择一个 User-Agent headers = {'User-Agent': random.choice(user_agents)} async with session.get(url, headers=headers) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: response = await fetch(session, 'https://example.com') print(response) # 运行主函数 asyncio.run(main())
3. 结合 Scrapy 使用代理和随机更换 User-Agent
3.1 设置代理
在 Scrapy 中,可以通过中间件设置代理服务器。
3.1.1 创建中间件
在
middlewares.py
文件中创建一个中间件来设置代理。import random class ProxyMiddleware: def __init__(self): self.proxies = [ 'http://123.45.67.89:8080', 'http://98.76.54.32:8080' ] def process_request(self, request, spider): proxy = random.choice(self.proxies) request.meta['proxy'] = proxy
3.1.2 启用中间件
在
settings.py
文件中启用中间件。DOWNLOADER_MIDDLEWARES = { 'myproject.middlewares.ProxyMiddleware': 750, }
3.2 随机更换 User-Agent
3.2.1 创建中间件
在
middlewares.py
文件中创建一个中间件来随机更换 User-Agent。import random class RandomUserAgentMiddleware: def __init__(self): self.user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' ] def process_request(self, request, spider): user_agent = random.choice(self.user_agents) request.headers['User-Agent'] = user_agent
3.2.2 启用中间件
在
settings.py
文件中启用中间件。DOWNLOADER_MIDDLEWARES = { 'myproject.middlewares.RandomUserAgentMiddleware': 750, }
验证码处理:对于包含验证码的登录过程,可能需要使用OCR技术或者第三方服务来识别验证码。
1. 使用 OCR 技术
1.1 安装必要的库
首先,确保你已经安装了
pytesseract
和Pillow
库。pytesseract
是一个用于调用 Tesseract OCR 引擎的 Python 包,Pillow
是一个图像处理库。pip install pytesseract pillow
1.2 下载并安装 Tesseract OCR
你需要下载并安装 Tesseract OCR 引擎。根据你的操作系统,下载和安装方法如下:
- Windows: 从 Tesseract 官方 GitHub 页面 下载安装包。
- macOS: 使用 Homebrew 安装:
brew install tesseract
- Linux: 使用包管理器安装:
sudo apt-get install tesseract-ocr
1.3 使用
pytesseract
识别验证码import pytesseract from PIL import Image # 读取验证码图片 image = Image.open('captcha.png') # 使用 pytesseract 识别验证码 captcha_text = pytesseract.image_to_string(image) # 打印识别结果 print(captcha_text)
2. 使用第三方服务
2.1 使用 2Captcha
2Captcha 是一个常用的第三方验证码识别服务。它提供了一个 API,可以轻松地将验证码发送给他们的服务器进行识别。
2.1.1 注册并获取 API 密钥
首先,注册一个 2Captcha 账户并获取 API 密钥。
2.1.2 安装
2captcha-python
库pip install 2captcha-python
2.1.3 使用 2Captcha 识别验证码
from twocaptcha import TwoCaptcha import requests from PIL import Image # 初始化 2Captcha 客户端 solver = TwoCaptcha('YOUR_API_KEY') # 读取验证码图片 with open('captcha.png', 'rb') as f: captcha_image = f.read() # 发送验证码图片到 2Captcha 服务器 result = solver.normal(captcha_image) # 打印识别结果 print(result['code'])
3. 综合示例:使用 OCR 和第三方服务处理验证码登录
下面是一个综合示例,展示如何使用 OCR 技术和第三方服务处理包含验证码的登录过程。
3.1 使用 OCR 技术
import requests from bs4 import BeautifulSoup import pytesseract from PIL import Image # 获取登录页面 login_url = 'https://example.com/login' response = requests.get(login_url) soup = BeautifulSoup(response.text, 'html.parser') # 获取验证码图片 URL captcha_img_url = soup.find('img', {'id': 'captcha'}).get('src') # 下载验证码图片 captcha_response = requests.get(captcha_img_url) with open('captcha.png', 'wb') as f: f.write(captcha_response.content) # 使用 pytesseract 识别验证码 captcha_text = pytesseract.image_to_string(Image.open('captcha.png')).strip() # 构建登录请求 login_data = { 'username': 'your_username', 'password': 'your_password', 'captcha': captcha_text } # 发送登录请求 response = requests.post(login_url, data=login_data) # 打印登录结果 print(response.text)
3.2 使用 2Captcha
import requests from bs4 import BeautifulSoup from twocaptcha import TwoCaptcha # 初始化 2Captcha 客户端 solver = TwoCaptcha('YOUR_API_KEY') # 获取登录页面 login_url = 'https://example.com/login' response = requests.get(login_url) soup = BeautifulSoup(response.text, 'html.parser') # 获取验证码图片 URL captcha_img_url = soup.find('img', {'id': 'captcha'}).get('src') # 下载验证码图片 captcha_response = requests.get(captcha_img_url) with open('captcha.png', 'wb') as f: f.write(captcha_response.content) # 发送验证码图片到 2Captcha 服务器 result = solver.normal('captcha.png') # 获取识别结果 captcha_text = result['code'] # 构建登录请求 login_data = { 'username': 'your_username', 'password': 'your_password', 'captcha': captcha_text } # 发送登录请求 response = requests.post(login_url, data=login_data) # 打印登录结果 print(response.text)
4. 处理复杂验证码
对于复杂的验证码(如扭曲的字符、干扰线等),简单的 OCR 技术可能无法准确识别。在这种情况下,可以考虑以下几种方法:
- 训练自定义模型:使用深度学习框架(如 TensorFlow 或 PyTorch)训练自定义的验证码识别模型。
- 使用更专业的第三方服务:除了 2Captcha,还有其他专业服务如 Anti-Captcha、Capmonster 等。
- 手动验证:在某些情况下,可以设计一个流程,将验证码发送给人类进行手动验证。
反爬虫策略:了解常见的反爬虫机制,并学习如何绕过这些限制。
1. 常见的反爬虫机制
1.1 IP 封禁
网站可能会记录访问者的 IP 地址,并在短时间内检测到大量请求时封禁该 IP。
1.2 User-Agent 检测
网站会检查请求头中的 User-Agent,如果发现不是常见的浏览器 User-Agent,可能会拒绝请求。
1.3 验证码
网站会在登录或关键操作时显示验证码,以防止自动化访问。
1.4 JavaScript 渲染
一些网站使用 JavaScript 动态加载内容,普通的 HTTP 请求无法获取这些内容。
1.5 Cookies 和 Session
网站可能会通过设置 Cookies 和 Session 来跟踪用户的会话状态,防止未授权访问。
1.6 频率限制
网站可能会限制每个 IP 在一定时间内的请求次数,超过限制后会暂时封禁该 IP。
2. 绕过反爬虫限制的策略
2.1 使用代理服务器
通过使用代理服务器,可以隐藏真实的 IP 地址,避免被封禁。
2.1.1 使用
requests
库import requests import random # 定义代理列表 proxies = [ 'http://123.45.67.89:8080', 'http://98.76.54.32:8080' ] # 随机选择一个代理 proxy = random.choice(proxies) # 发送请求 response = requests.get('https://example.com', proxies={'http': proxy, 'https': proxy}) # 打印响应内容 print(response.text)
2.1.2 使用
aiohttp
库import aiohttp import asyncio import random # 定义代理列表 proxies = [ 'http://123.45.67.89:8080', 'http://98.76.54.32:8080' ] async def fetch(session, url): # 随机选择一个代理 proxy = random.choice(proxies) async with session.get(url, proxy=proxy) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: response = await fetch(session, 'https://example.com') print(response) # 运行主函数 asyncio.run(main())
2.2 随机更换 User-Agent
通过随机更换 User-Agent,可以模拟不同的浏览器访问,降低被检测的风险。
2.2.1 使用
requests
库import requests import random # 定义 User-Agent 列表 user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' ] # 随机选择一个 User-Agent headers = {'User-Agent': random.choice(user_agents)} # 发送请求 response = requests.get('https://example.com', headers=headers) # 打印响应内容 print(response.text)
2.2.2 使用
aiohttp
库import aiohttp import asyncio import random # 定义 User-Agent 列表 user_agents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' ] async def fetch(session, url): # 随机选择一个 User-Agent headers = {'User-Agent': random.choice(user_agents)} async with session.get(url, headers=headers) as response: return await response.text() async def main(): async with aiohttp.ClientSession() as session: response = await fetch(session, 'https://example.com') print(response) # 运行主函数 asyncio.run(main())
2.3 处理验证码
使用 OCR 技术或第三方服务来识别验证码。
2.3.1 使用 OCR 技术
import pytesseract from PIL import Image # 读取验证码图片 image = Image.open('captcha.png') # 使用 pytesseract 识别验证码 captcha_text = pytesseract.image_to_string(image).strip() # 打印识别结果 print(captcha_text)
2.3.2 使用 2Captcha
from twocaptcha import TwoCaptcha import requests # 初始化 2Captcha 客户端 solver = TwoCaptcha('YOUR_API_KEY') # 下载验证码图片 captcha_response = requests.get('https://example.com/captcha.png') with open('captcha.png', 'wb') as f: f.write(captcha_response.content) # 发送验证码图片到 2Captcha 服务器 result = solver.normal('captcha.png') # 获取识别结果 captcha_text = result['code'] # 打印识别结果 print(captcha_text)
2.4 处理 JavaScript 渲染
使用
Selenium
或Pyppeteer
等库来处理 JavaScript 渲染的页面。2.4.1 使用
Selenium
from selenium import webdriver # 创建 WebDriver 对象 driver = webdriver.Chrome() # 打开网页 driver.get('https://example.com') # 获取动态加载的内容 content = driver.page_source # 打印内容 print(content) # 关闭浏览器 driver.quit()
2.4.2 使用
Pyppeteer
import asyncio from pyppeteer import launch async def main(): # 启动浏览器 browser = await launch() page = await browser.newPage() # 打开网页 await page.goto('https://example.com') # 获取动态加载的内容 content = await page.content() # 打印内容 print(content) # 关闭浏览器 await browser.close() # 运行主函数 asyncio.run(main())
2.5 处理 Cookies 和 Session
保持会话状态,确保每次请求都携带相同的 Cookies。
2.5.1 使用
requests
库import requests # 创建会话对象 session = requests.Session() # 发送请求 response = session.get('https://example.com') # 打印响应内容 print(response.text)
2.5.2 使用
aiohttp
库import aiohttp import asyncio async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): # 创建会话对象 async with aiohttp.ClientSession() as session: response = await fetch(session, 'https://example.com') print(response) # 运行主函数 asyncio.run(main())
2.6 控制请求频率
通过控制请求频率,避免因请求过于频繁而被封禁。
2.6.1 使用
time.sleep
import requests import time urls = ['https://example.com/page1', 'https://example.com/page2'] for url in urls: response = requests.get(url) print(response.text) time.sleep(1) # 每次请求之间暂停1秒
2.6.2 使用
asyncio.sleep
import aiohttp import asyncio async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): urls = ['https://example.com/page1', 'https://example.com/page2'] async with aiohttp.ClientSession() as session: for url in urls: response = await fetch(session, url) print(response) await asyncio.sleep(1) # 每次请求之间暂停1秒 # 运行主函数 asyncio.run(main())