- 本书赞誉
- 前言
- 目标读者
- 不适合阅读本书的读者
- 本书结构
- 什么是数据处理
- 遇到困难怎么办
- 排版约定
- 使用代码示例
- 致谢
- 第 1 章 Python 简介
- 第 2 章 Python 基础
- 第 3 章 供机器读取的数据
- 第 4 章 处理 Excel 文件
- 第 5 章 处理 PDF 文件 以及用 Python 解决问题
- 第 6 章 数据获取与存储
- 第 7 章 数据清洗:研究、匹配与格式化
- 第 8 章 数据清洗:标准化和脚本化
- 第 9 章 数据探索和分析
- 第 10 章 展示数据
- 第 11 章 网页抓取:获取并存储网络数据
- 第 12 章 高级网页抓取:屏幕抓取器与爬虫
- 第 13 章 应用编程接口
- 第 14 章 自动化和规模化
- 第 15 章 结论
- 附录 A 编程语言对比
- 附录 B 初学者的 Python 学习资源
- 附录 C 学习命令行
- 附录 D 高级 Python 设置
- 附录 E Python 陷阱
- 附录 F IPython 指南
- 附录 G 使用亚马逊网络服务
- 关于作者
- 关于封面
12.3 网络:互联网的工作原理 以及为什么它会让脚本崩溃
取决于运行抓取脚本的频率,以及每个脚本工作的重要性,你可能会碰到网络问题。是的,互联网正在尝试破坏你的脚本。为什么?因为互联网认为如果你真的在乎,你会重试。在网页抓取世界里丢失的连接、代理问题以及超时问题普遍存在。然而,有一些方法可以缓解这些问题。
在浏览器中,如果有页面信息没有正确加载,你就会点击刷新,立即发送另一个请求。对于抓取器,你可以模仿这种行为。如果你正在使用 Selenium,刷新内容会极其简单。 Selenium 的 webdriver 对象有一个 refresh 函数,就像浏览器一样。如果你已经填充了一个表单,需要重新提交表单,前进至下一页(有时这类似于浏览器的行为)。如果你需要同警告或弹出窗口交互,Selenium 提供了接受或拒绝信息所需的工具。
Scrapy 有内置的重试中间件。要启用它,你只需将它添加到项目的 settings.py 文件的中间件列表中。中间件(https://doc.scrapy.org/en/latest/topics/downloader-middleware.html#module-scrapy.contrib.downloadermiddleware.retry)希望你在设置中设定一些默认值,以便它知道哪些 HTTP 响应码需要重试(例如,它需要只在返回码为 500 的时候重试吗?),以及重试的次数。
如果你没有指定这些值,它仍然会使用文档中列出的默认值工作。如果你看到网络错误,然后下载等待时间(另外一个全局设置变量)变长,建议你从 10 次重试开始,或者检查收到的返回码,看看脚本是否访问网站过于频繁。
如果你正在使用自己的 Python 脚本和 LXML 或 BeautifulSoup,最好是捕获这些错误并确定处理它们的方法。大多数时间里,你会注意到 urllib2.HTTPError(https://docs.python.org/2/library/urllib2.html#urllib2.HTTPError)异常的优势;或者,如果你正在使用 requests,代码不会加载内容,并且失败。在 Python 中使用一个 try...except 代码块,你的代码可能看起来像下面一样。
import requests import urllib2 resp = requests.get('http://sisinmaru.blog17.fc2.com/') if resp.status_code == 404: ➊ print 'Oh no!!! We cannot find Maru!!' elif resp.status_code == 500: print 'Oh no!!! It seems Maru might be overloaded.' elif resp.status_code in [403, 401]: print 'Oh no!! You cannot have any Maru!' try: resp = urllib2.urlopen('http://sisinmaru.blog17.fc2.com/') ➋ except urllib2.URLError: ➌ print 'Oh no!!! We cannot find Maru!!' except urllib2.HTTPError, err: ➍ if err.code == 500: ➎ print 'Oh no!!! It seems Maru might be overloaded.' elif err.code in [403, 401]: print 'Oh no!! You cannot have any Maru!' else: print 'No Maru for you! %s' % err.code ➏ except Exception as e: ➐ print e
❶ 当使用 requests 库来查找网络错误时,检查响应的 status_code。这个属性会返回一个代表在 HTTP 响应中收到的代码的整数。这行代码测试响应是否为 404 错误。
❷ 如果正在使用 urllib2,将请求放在一个 try 语句中(正如这行代码一样)。
❸ 可能会从 urllib2 中看到的一个异常是 URLError。编写一个捕获方法是好的想法。如果它不能解析域名,可能会抛出这个错误。
❹ 可能看到的另外一个异常是 HTTPError。任何有关 HTTP 请求错误的响应都会抛出这个错误。通过添加冒号和 err,捕获了错误,并且将它保存在变量 err 中,这样可以打印错误到日志。
❺ 现在捕捉到了错误,并且将其赋值给前行代码中的 err,这行代码判断 code 属性,来查看 HTTP 错误码。
❻ 对于所有其他的 HTTP 错误,这行代码使用 else 通过格式化它到字符串,来展示错误码。
❼ 这行代码捕获其他所有可能碰到的错误,并且展示错误信息。赋值异常给变量 e,并且打印它,这样可以阅读异常信息。
巧妙地设计脚本,让它尽可能地抗失败,这是一个重要的步骤(第 14 章会更详细地讨论);同时确保在代码中有合适的 try...except 代码块来解释错误,也是进程中重要的一部分。除了 HTTP 错误,有些时候,页面花费过长的时间来加载。如果抓取器响应缓慢或碰到了延迟问题,我们可能会调整超时时间。
什么是延迟?从网络角度来讲,这是数据从一个地点发送到另一个地点需要的时间。往返延迟是从计算机发送请求到服务器,并且得到响应花费的时间。延迟因为数据的传输而存在,有时数据需要传送几千千米,来完成请求。
当编写和规模化脚本时,考虑延迟是很好的。如果脚本所连接的站点托管在另一个国家,你会经历网络延迟。因此你需要相应地调整超时时间,或者创建一个距离目标端点近的服务器。如果想要添加超时时间到 Selenium 和 Ghost.py 脚本,你可以在抓取工作开始的时候,直接添加到脚本中。对于 Selenium,使用 set_page_load_timeout(http://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webdriver.WebDriver.set_page_load_timeout)方法,或使用隐式 / 显式的等待(http://selenium-python.readthedocs.io/waits.html),这样浏览器会等待代码中特定的部分加载。对于 Ghost.py,你可能需要传递 wait_timeout 参数,像 Ghost 类文档中定义的那样(http://ghost-py.readthedocs.io/en/latest/#ghost.Ghost)。
对于 Scrapy,抓取器的异步特性和对特定的 URL 重试若干次的能力,让超时设置变成了一个略微难办的问题。当然,你可以在 Scrapy 设置中使用 DOWNLOAD_TIMEOUT(http://doc.scrapy.org/en/latest/topics/settings.html#download-timeout)直接改变超时时间。
如果你正在编写自己的 Python 脚本,并且使用 LXML 或 BeautifulSoup 来解析页面,添加超时到调用是你的职责。如果使用 requests 或 urllib2,你可以在调用页面的时候直接这样做。在 requests 中,你可以直接将其作为一个参数,添加到 get 请求中(http://docs.python-requests.org/en/latest/user/quickstart/#timeouts)。对于 urllib2,你需要传递超时时间,作为 urlopen 方法(https://docs.python.org/2/library/urllib2.html#urllib2.urlopen)的参数之一。
如果你正经历持续的网络方面的问题,并且脚本需要依据一个稳定的日程运行,建议你创建一些日志,尝试在另外一个网络上运行(即不是你的家庭网络,来判断你的家庭互联网连接是否存在问题),并且测试是否在一个非高峰时间段运行会有帮助。
脚本在每天下午 5 点还是上午 5 点钟更新对你是否很重要?很可能在下午 5 点钟你的本地互联网服务提供商会非常繁忙,而上午 5 点钟可能会很安静。如果在高峰时段你的家庭网络很难做成事,那么很可能你的脚本也同样做不了什么!
除了网络问题之外,你可能会找到其他破坏抓取脚本的问题,比如互联网在不停变化这一事实。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论