- 内容提要
- 作者简介
- 技术评审者简介
- 致谢
- 译者序 会编程的人不一样
- 前言
- 本书的读者对象
- 编码规范
- 什么是编程
- 本书简介
- 下载和安装 Python
- 启动 IDLE
- 如何寻求帮助
- 聪明地提出编程问题
- 小结
- 第一部分 Python 编程基础
- 第1章 Python 基础
- 第2章 控制流
- 第3章 函数
- 第4章 列表
- 第5章 字典和结构化数据
- 第6章 字符串操作
- 第二部分 自动化任务
- 第7章 模式匹配与正则表达式
- 第8章 读写文件
- 第9章 组织文件
- 第10章 调试
- 第11章 从 Web 抓取信息
- 第12章 处理 Excel 电子表格
- 第13章 处理 PDF 和 Word 文档
- 第14章 处理 CSV 文件和 JSON 数据
- 第15章 保持时间、计划任务和启动程序
- 第16章 发送电子邮件和短信
- 第17章 操作图像
- 第18章 用 GUI 自动化控制键盘和鼠标
- 附录A 安装第三方模块
- 附录B 运行程序
- 附录C 习题答案
11.7 项目:下载所有 XKCD 漫画
博客和其他经常更新的网站通常有一个首页,其中有最新的帖子,以及一个“前一篇”按钮,将你带到以前的帖子。然后那个帖子也有一个“前一篇”按钮,以此类推。这创建了一条线索,从最近的页面,直到该网站的第一个帖子。如果你希望拷贝该网站的内容,在离线的时候阅读,可以手工导航至每个页面并保存。但这是很无聊的工作,所以让我们写一个程序来做这件事。
XKCD 是一个流行的极客漫画网站,它符合这个结构(参见图 11-6)。首页http://xkcd.com/有一个“Prev”按钮,让用户导航到前面的漫画。手工下载每张漫画要花较长的时间,但你可以写一个脚本,在几分钟内完成这件事。
下面是程序要做的事:
· 加载主页;
· 保存该页的漫画图片;
· 转入前一张漫画的链接;
· 重复直到第一张漫画。
图11-6 XKCD,“关于浪漫、讽刺、数学和语言的漫画网站”
这意味着代码需要做下列事情:
· 利用requests模块下载页面。
· 利用Beautiful Soup找到页面中漫画图像的URL。
· 利用iter_content()下载漫画图像,并保存到硬盘。
· 找到前一张漫画的链接URL,然后重复。
打开一个新的文件编辑器窗口,将它保存为downloadXkcd.py。
第1步:设计程序
打开一个浏览器的开发者工具,检查该页面上的元素,你会发现下面的内容:
· 漫画图像文件的URL,由一个< img>元素的href属性给出。
· < img>元素在< div id="comic">元素之内。
· Prev按钮有一个rel HTML属性,值是prev。
· 第一张漫画的Prev按钮链接到http://xkcd.com/# URL,表明没有前一个页面了。
让你的代码看起来像这样:
#! python3 # downloadXkcd.py - Downloads every single XKCD comic. import requests, os, bs4 url = 'http://xkcd.com' # starting url os.makedirs('xkcd', exist_ok=True) # store comics in ./xkcd while not url.endswith('#'): # TODO: Download the page. # TODO: Find the URL of the comic image. # TODO: Download the image. # TODO: Save the image to ./xkcd. # TODO: Get the Prev button's url. print('Done.')
你会有一个url变量,开始的值是'http://xkcd.com',然后反复更新(在一个for循环中),变成当前页面的Prev链接的URL。在循环的每一步,你将下载URL上的漫画。如果URL以'#'结束,你就知道需要结束循环。
将图像文件下载到当前目录的一个名为xkcd的文件夹中。调用os.makedirs()函数。确保这个文件夹存在,并且关键字参数exist_ok=True在该文件夹已经存在时,防止该函数抛出异常。剩下的代码只是注释,列出了剩下程序的大纲。
第2步:下载网页
我们来实现下载网页的代码。让你的代码看起来像这样:
#! python3 # downloadXkcd.py - Downloads every single XKCD comic. import requests, os, bs4 url = 'http://xkcd.com' # starting url os.makedirs('xkcd', exist_ok=True) # store comics in ./xkcd while not url.endswith('#'): # Download the page. print('Downloading page %s...' % url) res = requests.get(url) res.raise_for_status() soup = bs4.BeautifulSoup(res.text) # TODO: Find the URL of the comic image. # TODO: Download the image. # TODO: Save the image to ./xkcd. # TODO: Get the Prev button's url. print('Done.')
首先,打印url,这样用户就知道程序将要下载哪个URL。然后利用requests模块的request.get()函数下载它。像以往一样,马上调用Response对象的raise_for_status()方法,如果下载发生问题,就抛出异常,并终止程序。否则,利用下载页面的文本创建一个BeautifulSoup对象。
第3步:寻找和下载漫画图像
让你的代码看起来像这样:
#! python3 # downloadXkcd.py - Downloads every single XKCD comic. import requests, os, bs4 --snip-- # Find the URL of the comic image. comicElem = soup.select('#comic img') if comicElem == []: print('Could not find comic image.') else: comicUrl = 'http:' comicElem[0].get('src') # Download the image. print('Downloading image %s...' % (comicUrl)) res = requests.get(comicUrl) res.raise_for_status() # TODO: Save the image to ./xkcd. # TODO: Get the Prev button's url. print('Done.')
用开发者工具检查XKCD主页后,你知道漫画图像的< img>元素是在一个< div>元素中,它带有的id属性设置为comic。所以选择器'#comic img'将从BeautifulSoup对象中选出正确的< img>元素。
有一些XKCD页面有特殊的内容,不是一个简单的图像文件。这没问题,跳过它们就好了。如果选择器没有找到任何元素,那么soup.select('#comic img')将返回一个空的列表。出现这种情况时,程序将打印一条错误消息,不下载图像,继续执行。
否则,选择器将返回一个列表,包含一个< img>元素。可以从这个< img>元素中取得src属性,将它传递给requests.get(),下载这个漫画的图像文件。
第4步:保存图像,找到前一张漫画
让你的代码看起来像这样:
#! python3 # downloadXkcd.py - Downloads every single XKCD comic. import requests, os, bs4 --snip-- # Save the image to ./xkcd. imageFile = open(os.path.join('xkcd', os.path.basename(comicUrl)), 'wb') for chunk in res.iter_content(100000): imageFile.write(chunk) imageFile.close() # Get the Prev button's url. prevLink = soup.select('a[rel="prev"]')[0] url = 'http://xkcd.com' + prevLink.get('href') print('Done.')
这时,漫画的图像文件保存在变量res中。你需要将图像数据写入硬盘的文件。
你需要为本地图像文件准备一个文件名,传递给 open()。comicUrl的值类似'http://imgs.xkcd.com/comics/heartbleed_explanation.png'。你可能注意到,它看起来很像文件路径。实际上,调用os.path.basename()时传入comicUrl,它只返回URL的最后部分:'heartbleed_explanation.png'。你可以用它作为文件名,将图像保存到硬盘。用os.path.join()连接这个名称和xkcd文件夹的名称,这样程序就会在Windows下使用倒斜杠(\),在OS X和Linux下使用斜杠(/)。既然你最后得到了文件名,就可以调用open(),用'wb'模式打开一个新文件。
回忆一下本章早些时候,保存利用 Requests 下载的文件时,你需要循环处理iter_content()方法的返回值。for循环中的代码将一段图像数据写入文件(每次最多10万字节),然后关闭该文件。图像现在保存到硬盘中。
然后,选择器'a[rel="prev"]'识别出rel属性设置为prev的< a>元素,利用这个< a>元素的href属性,取得前一张漫画的URL,将它保存在url中。然后while循环针对这张漫画,再次开始整个下载过程。
这个程序的输出看起来像这样:
Downloading page http://xkcd.com... Downloading image http://imgs.xkcd.com/comics/phone_alarm.png... Downloading page http://xkcd.com/1358/... Downloading image http://imgs.xkcd.com/comics/nro.png... Downloading page http://xkcd.com/1357/... Downloading image http://imgs.xkcd.com/comics/free_speech.png... Downloading page http://xkcd.com/1356/... Downloading image http://imgs.xkcd.com/comics/orbital_mechanics.png... Downloading page http://xkcd.com/1355/... Downloading image http://imgs.xkcd.com/comics/airplane_message.png... Downloading page http://xkcd.com/1354/... Downloading image http://imgs.xkcd.com/comics/heartbleed_explanation.png... --snip--
这个项目是一个很好的例子,说明程序可以自动顺着链接,从网络上抓取大量的数据。你可以从Beautiful Soup的文档了解它的更多功能:http://www. crummy.com/ software/BeautifulSoup/bs4/doc/.
第5步:类似程序的想法
下载页面并追踪链接,是许多网络爬虫程序的基础。类似的程序也可以做下面的事情:
· 顺着网站的所有链接,备份整个网站。
· 拷贝一个论坛的所有信息。
· 复制一个在线商店中所有产品的目录。
requests 和 BeautifulSoup 模块很了不起,只要你能弄清楚需要传递给requests.get()的URL。但是,有时候这并不容易找到。或者,你希望编程浏览的网站可能要求你先登录。selenium 模块将让你的程序具有执行这种复杂任务的能力。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论