如果你已经看到这节课,说明你已经对网页爬取的工作原理有了一定的了解, 并且知道如何使用强大的BeautifulSoup从HTML中提取所需的数据。 不过,网页爬取的世界并不像教科书写得那么顺利。有时候,想要获取数据的 美好梦想可能会变成与各种错误作斗争的噩梦。所以,让我们聊聊如何避开这些 潜在的坑,并让我们的爬虫尽可能稳定。
1. 网页爬取中的常见错误
404错误和其他HTTP错误
经典问题:你尝试获取一个网页,却收到一条自豪的“404 Not Found”。 这可能是因为网页被删除或移动了。其他常见的HTTP错误包括403(Forbidden), 500(Internal Server Error)和503(Service Unavailable)。
HTML结构变化
你花了很多时间写代码提取数据,结果第二天网站决定“换个样子”并修改了HTML结构。 嗐,又得重写一遍!
请求数量限制
有些网站会开始怀疑不对劲,当一整天都被爬虫“亲密接触”。最好的情况下, 你会被暂时封禁,而最坏的情况下,永久封禁。
加载时间和超时
有时候页面加载很慢,如果等待超过了默认的超时时间,你的脚本可能就会崩溃。
2. 错误处理方法
使用try-except
你的脚本不应该因为某个意外就直接崩溃。添加try-except块可以捕捉错误, 并让你的爬虫在遇到问题时继续正常运行。
import requests
from bs4 import BeautifulSoup
url = 'http://example.com/some-nonexistent-page'
try:
response = requests.get(url)
response.raise_for_status() # 引发错误的HTTP响应
except requests.exceptions.HTTPError as errh:
print("HTTP错误:", errh)
except requests.exceptions.ConnectionError as errc:
print("连接错误:", errc)
except requests.exceptions.Timeout as errt:
print("超时错误:", errt)
except requests.exceptions.RequestException as err:
print("其他错误:", err)
好的脚本不仅仅捕捉异常,还会针对每种错误类型采取相应的行动。 如果IP被封了,就换用下一个代理。如果网站挂了,那就先爬取别的页面。 如果页面中某些原本应该存在的元素不见了,可以通知爬虫的拥有者更新解析脚本并发送email。
日志记录
“要日志干啥?”你可能会问。日志就是你的第二双眼睛。 它能帮助你快速找到问题所在并修复错误。
import logging
logging.basicConfig(filename='scraper.log', level=logging.INFO)
try:
# 你的爬取代码
pass
except Exception as e:
logging.error("发生异常", exc_info=True)
使用超时和重试机制
有时候,只需要稍微等等再试一次。超时和重试机制就可以派上用场。
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
except requests.exceptions.Timeout:
print("超时发生。重试中...")
# 再次请求或采取其他措施
3. 稳定爬取的实例
带错误处理的简单爬虫
让我们创建一个小型但可靠的爬虫,它能够处理一些常见错误。
import requests
from bs4 import BeautifulSoup
import time
import logging
logging.basicConfig(filename='scraper.log', level=logging.INFO)
url = 'http://example.com/some-nonexistent-page'
def fetch_html(url):
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
return response.text
except requests.exceptions.HTTPError as errh:
logging.error("HTTP错误: %s", errh)
except requests.exceptions.ConnectionError as errc:
logging.error("连接错误: %s", errc)
except requests.exceptions.Timeout as errt:
logging.warning("超时发生。重试中...")
time.sleep(1) # 稍等片刻再试
return fetch_html(url)
except requests.exceptions.RequestException as err:
logging.error("其他错误 %s", err)
return None
html_content = fetch_html(url)
if html_content:
soup = BeautifulSoup(html_content, 'html.parser')
# 你的数据提取代码
else:
print("无法获取页面内容。")
分批保存数据
为了避免因为意外丢失已经提取的数据,可以分批保存。 例如,如果你在从一系列页面中提取信息,可以在每完成一部分时保存结果, 从而将数据丢失的风险降至最低。
import csv
def save_to_csv(data, filename='data.csv'):
with open(filename, mode='a', newline='') as file:
writer = csv.writer(file)
writer.writerow(data)
这样,即使脚本在工作中途崩溃,你也不会丢失所有数据,并可以从最后一个保存点继续。
你爬取的页面可能部分发生变化,但大多数数据仍然可以使用。 如果只有少部分数据缺失,完全停止爬取并丢弃珍贵的数据可不好。
GO TO FULL VERSION