Python 小爬虫 - 爬取今日头条街拍美女图

先实际感受一下我们要抓取的福利是什么?点击 今日头条,在搜索栏输入街拍 两个字,点开任意一篇文章,里面的图片即是我们要抓取的内容。

可以看到搜索结果默认返回了 20 篇文章,当页面滚动到底部时头条通过 ajax 加载更多文章,浏览器按下 F12 打开调试工具(我的是 Chrome),点击 Network 选项,尝试加载更多的文章,可以看到相关的 http 请求:

可以看到请求的 URL(Request URL)为:http://www.toutiao.com/search_content/, 其请求参数为:

很容易猜测 offset 表示偏移量,即已经请求的文章数;format 为返回格式,这里返回的是 json 格式的数据;keyword 是我们的搜索关键字;autoload 应该是自动加载的指示标志,无关紧要;count 为请求的新文章数量;_ 应该是请求发起时的时间戳。将请求的 URL 和这些查询参数拼接即组成完整的 Request URL,例如这次的 Request URL 是: http://www.toutiao.com/search_content/?offset=20&format=json&keyword=%E8%A1%97%E6%8B%8D&autoload=true&count=20&_=1480675595492。

先让我们来看看这个请求为我们返回了什么样的数据。

import json

from pprint import pprint
from urllib import request

url = "http://www.toutiao.com/search_content/?offset=20&format=json&keyword=%E8%A1%97%E6%8B%8D&autoload=true&count=20&_=1480675595492"

with request.urlopen(url) as res:
    d = json.loads(res.read().decode())
    print(d)

这里我们首先通过 request.urlopen(url) 向这个 url 发送请求,返回的数据保存在 res 中,res 是一个 HttpResponse 对象,通过调用其 read 方法获取实际返回的内容,由于 read 方法返回的是 Python 的 bytes 类型的字符串,通过调用其 decode 方法将其编码成 string 类型字符串,默认为 UTF-8 编码。由于数据以 json 格式返回,因此通过 json.load 方法将其转为 Python 的字典形式。

打印出这个字典,可以看到字典中有一个键 ‘data’ 对应着一个由字典组成的列表的值,分析可知这个值就是返回的全部文章的数据列表,稍微修改一下代码,来看看 ‘data’ 对应的值是什么样的:

with request.urlopen(url) as res:
    d = json.loads(res.read().decode())
    d = d.get('data')
    pprint(d)

这里使用了 pprint 让字典打印的出来的值更加的格式化,便于分析。可以看到这是一个由字典组成的列表,列表的每一个项代表一篇文章,包含了文章的全部基本数据,例如标题,文章的 URL 等。于是我们可以通过如下的方式来获取我们本次请求的全部文章的 URL 列表:

urls = [article.get('article_url') for article in d if article.get('article_url')]

这里使用了列表推导式,循环文章列表,通过 get('article_url') 获取到文章的 URL,加上 if 判断条件是为了防止因为数据缺失而得到空的文章 URL。我们将通过不断请求这些文章的 URL,读取其内容,并把图片提取出来保存到我们的硬盘里。

先来处理一篇文章,看看我们如何把文章里的全部图片提取出来。

随便点开一个文章链接,按 F12 查看网页源代码,可以看到文章的主体部分位于一个 id="article-main"

的 div 里。这个 div 下有 h1 标签表示文章标题,另外一系列 img 标签,其 src 属性即保存着图片所在的链接,于是我们通过访问这些链接把图片下载下来,看看具体怎么做:

url = "http://www.toutiao.com/a6351879148420235522/"

with request.urlopen(url) as res:
    soup = BeautifulSoup(res.read().decode(errors='ignore'), 'html.parser')
    article_main = soup.find('div', id='article-main')
    photo_list = [photo.get('src') for photo in article_main.find_all('img') if photo.get('src')]
    print(photo_list)

# 输出:
['http://p9.pstatp.com/large/111200020f54729cd558', 'http://p3.pstatp.com/large/11100005d3e8b9e69a88', 'http://p3.pstatp.com/large/106b00058387c12351c7', ...]

这里我们请求文章的 URL,将返回的内容(html)传递给 BeautifulSoup 为我们做解析。通过 find 方法找到 article-main 对应的 div 块,在该 div 块下继续使用 find_all 方法搜寻全部的 img 标签,并提取其 src 属性对应的值,于是我们便获得了该文章下全部图片的 URL 列表。 现在要做的就是继续请求这些图片的 URL,并把返回的图片数据保存到硬盘里。以一张图片示例:

photo_url = "http://p9.pstatp.com/large/111200020f54729cd558"
photo_name = photo_url.rsplit('/', 1)[-1] + '.jpg'

with request.urlopen(photo_url) as res, open(photo_name, 'wb') as f:
    f.write(res.read())

此时就可以在当前目录下看到我们保存下来的图片了。这里我们使用了 URL 最后一段的数字做为图片的文件名,并将其保存为 jpg 的格式。

基本步骤就是这么多了,整理下爬取流程:

  1. 指定查询参数,向 http://www.toutiao.com/search_content/ 提交我们的查询请求。
  2. 从返回的数据(JSON 格式)中解析出全部文章的 URL,分别向这些文章发送请求。
  3. 从返回的数据(HTML 格式)提取出文章的标题和全部图片链接。
  4. 再分别向这些图片链接发送请求,将返回的图片输入保存到本地。
  5. 修改查询参数,以使服务器返回新的文章数据,继续第一步。

完整代码挂在了 GitHub 上 ,代码中已经加了详细的注释,我运行此代码后一共爬取了大概 1000 多张图片。

-- EOF --

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Web 开发

利用 Promise 实现任务流的自动重试

微信小程序不支持 HTTP 的 cookie ,其会话机制是通过开发自己维护一个 session_id 在小程序的本地存储中,每次调用 wx.request 的...

1640
来自专栏Python入门

如何用Python来制作简单的爬虫,爬取到你想要的图片

在我们日常上网浏览网页的时候,经常会看到一些好看的图片,我们就希望把这些图片保存下载,或者用户用来做桌面壁纸,或者用来做设计的素材。

1153
来自专栏北京马哥教育

看了还想看—普通权限及umask

权限在操作系统是尤为重要的,无论是windows和linux中,都少不了权限这么一说,权限的大小决定了你能操作些什么,在linux中,权限对目录和文件的意义是不...

3817
来自专栏闻道于事

IntelliJ IDEA 2018.3 重大升级(转)

2018.11.28 IntelliJ IDEA 2018.3 正式版发布。对于一个忠实爱好者,迫不及待的我下载了最新版本来体验下。而且 IDEA 今年的第三次...

3152
来自专栏魏艾斯博客www.vpsss.net

wordpress 无法建立到 wordpress org 安全连接的解决办法

网友求助,说安装 Avada 插件时遇到如下错误提示:wordpress 无法建立到 wordpress.org 的安全连接,请联系您的服务器管理员。询问网友得...

1502
来自专栏happyJared

Hexo,添加标题翻译插件

  hexo生成的默认文章链接格式是这样的:https://blog.mariojd.cn/2013/07/14/<Markdown file name>/,这...

1533
来自专栏coder修行路

jS正则和WEB框架Django的入门

JS正则 -test 判断字符串是否符合规定的正则表达式 -exec 获取匹配的数据 test的例子: ? 从上述的例子我们可以看出,如果rep.test匹配到...

2176
来自专栏趣谈编程

用户空间和内核空间是什么?

学习 Linux 时,经常可以看到两个词:User space(用户空间)和 Kernel space(内核空间)。

2.4K3
来自专栏魏艾斯博客www.vpsss.net

wordpress 无法建立到 wordpress org 安全连接的解决办法

网友求助,说安装 Avada 插件时遇到如下错误提示:wordpress 无法建立到 wordpress.org 的安全连接,请联系您的服务器管理员。询问网友得...

1723
来自专栏Android工程师的修仙之旅

bat批处理简介:Windows自动化之道

最近在工作中遇到一些纯粹重复的工作,最终都通过脚本方式达到了自动化,大大提高效率。比如之前每次发布zip包都需要手动编译lua文件、替换lua引用为二进制文件的...

2942

扫码关注云+社区

领取腾讯云代金券