一、爬取今日头条新闻
为什么要这么爬请看 获取JS动态内容
按 F12 查看源代码,选择 XHR (XHR是Ajax中的概念,表示XMLHTTPrequest),刷新下网页可以看到有这么几个 xhr 响应(有的网页在 js 内,例如京东商品评论商品参数)
先随便点开个看看, 查看 Preview, 可以看到这时城市分布。
再看看 focus,应该是我们想要的,点开一看,果然是
接着看看请求头 Heardes,可以看到它请求的 url 是这个 http://www.toutiao.com/api/pc/focus/
点开一看,这并不是乱码,而是我们想要获取数据的 json 格式
那么我们就可以写出我们的代码了
>>> import requests
>>> import json
>>> url = 'http://www.toutiao.com/api/pc/focus/'
>>> html = requests.get(url)
>>> web_data = html.text
>>> data = json.loads(web_data) #把 json 格式的数据转为python
>>> data
{'data': {'pc_feed_focus': [{'display_url': '/group/6399094723911008514/', 'media_url': 'http://toutiao.com/m3232597584', 'group_id': 6399094723911008514, 'has_image': False, 'image_url': 'http://p3.pstatp.com/origin/18a2000e3f19a682517d', 'has_video': False, 'title': '秘鲁暴雨洪水肆虐已致75死 多座桥梁断裂'}, {'display_url': '/group/6399235239927988481/', 'media_url': 'http://toutiao.com/m6159273532', 'group_id': 6399235239927988481, 'has_image': True, 'image_url': 'http://p3.pstatp.com/origin/18a4000b2c3f020d2672', 'has_video': False, 'title': '农田内现8米“巨型西瓜” 原是瓜农休息屋'}, {'display_url': '/group/6399373433771163906/', 'media_url': 'http://toutiao.com/m6159077688', 'group_id': 6399373433771163906, 'has_image': True, 'image_url': 'http://p3.pstatp.com/origin/18a3000e5352b8698692', 'has_video': False, 'title': '“抖森”和“大表哥”红毯相逢 一个玩合影一个高冷'}, {'display_url': '/group/6399240459256987906/', 'media_url': 'http://toutiao.com/m6159306637', 'group_id': 6399240459256987906, 'has_image': True, 'image_url': 'http://p3.pstatp.com/origin/17810004879f0f1d5d58', 'has_video': False, 'title': '女子冰壶世锦赛 中国队负捷克遭遇三连败'}, {'display_url': '/group/6398683043066102018/', 'media_url': 'http://toutiao.com/m3995104383', 'group_id': 6398683043066102018, 'has_image': True, 'image_url': 'http://p1.pstatp.com/origin/18a5000e3a385dce3833', 'has_video': False, 'title': '面目全非的经典 无托雷明登步枪难畅销'}, {'display_url': '/group/6399219019417092353/', 'media_url': 'http://toutiao.com/m6159077688', 'group_id': 6399219019417092353, 'has_image': True, 'image_url': 'http://p3.pstatp.com/origin/17810004880274aa5f39', 'has_video': False, 'title': '中国电影金扫帚奖颁奖典礼 柯震东得最佳男演员奖'}, {'display_url': '/group/6398681047375413506/', 'media_url': 'http://toutiao.com/m5784742177', 'group_id': 6398681047375413506, 'has_image': True, 'image_url': 'http://p1.pstatp.com/large/178100030f9ee4b453b1', 'has_video': False, 'title': '尴尬!默克尔访美被特朗普“甩脸” 握手请求遭无视'}, {'display_url': '/group/6398305109151138049/', 'media_url': 'http://toutiao.com/m5739097906', 'group_id': 6398305109151138049, 'has_image': True, 'image_url': 'http://p3.pstatp.com/origin/18a2000b7e1e6f9c3bab', 'has_video': False, 'title': '因材施教还是胡闹?细数分分钟刷三观的奇葩专业'}, {'display_url': '/group/6398869278900945153/', 'media_url': 'http://toutiao.com/m3232698963', 'group_id': 6398869278900945153, 'has_image': False, 'image_url': 'http://p3.pstatp.com/origin/18a1000d3cab1acc86b8', 'has_video': False, 'title': '贾静雯生下第三胎 前夫晒梧桐妹给自己的动人祝福'}, {'display_url': '/group/6398493215008538882/', 'media_url': 'http://toutiao.com/m6675759548', 'group_id': 6398493215008538882, 'has_image': True, 'image_url': 'http://p1.pstatp.com/origin/18a2000b7e76fded3cb3', 'has_video': False, 'title': '宏远力夺赛点 深圳功亏一篑'}]}, 'message': 'success'}
>>> data['data']['pc_feed_focus'] #新闻数据存在这里,接着迭代
[{'display_url': '/group/6399094723911008514/', 'media_url': 'http://toutiao.com/m3232597584', 'group_id': 6399094723911008514, 'has_image': False, 'image_url': 'http://p3.pstatp.com/origin/18a2000e3f19a682517d', 'has_video': False, 'title': '秘鲁暴雨洪水肆虐已致75死 多座桥梁断裂'}, {'display_url': '/group/6399235239927988481/', 'media_url': 'http://toutiao.com/m6159273532', 'group_id': 6399235239927988481, 'has_image': True, 'image_url': 'http://p3.pstatp.com/origin/18a4000b2c3f020d2672', 'has_video': False, 'title': '农田内现8米“巨型西瓜” 原是瓜农休息屋'}, {'display_url': '/group/6399373433771163906/', 'media_url': 'http://toutiao.com/m6159077688', 'group_id': 6399373433771163906, 'has_image': True, 'image_url': 'http://p3.pstatp.com/origin/18a3000e5352b8698692', 'has_video': False, 'title': '“抖森”和“大表哥”红毯相逢 一个玩合影一个高冷'}, {'display_url': '/group/6399240459256987906/', 'media_url': 'http://toutiao.com/m6159306637', 'group_id': 6399240459256987906, 'has_image': True, 'image_url': 'http://p3.pstatp.com/origin/17810004879f0f1d5d58', 'has_video': False, 'title': '女子冰壶世锦赛 中国队负捷克遭遇三连败'}, {'display_url': '/group/6398683043066102018/', 'media_url': 'http://toutiao.com/m3995104383', 'group_id': 6398683043066102018, 'has_image': True, 'image_url': 'http://p1.pstatp.com/origin/18a5000e3a385dce3833', 'has_video': False, 'title': '面目全非的经典 无托雷明登步枪难畅销'}, {'display_url': '/group/6399219019417092353/', 'media_url': 'http://toutiao.com/m6159077688', 'group_id': 6399219019417092353, 'has_image': True, 'image_url': 'http://p3.pstatp.com/origin/17810004880274aa5f39', 'has_video': False, 'title': '中国电影金扫帚奖颁奖典礼 柯震东得最佳男演员奖'}, {'display_url': '/group/6398681047375413506/', 'media_url': 'http://toutiao.com/m5784742177', 'group_id': 6398681047375413506, 'has_image': True, 'image_url': 'http://p1.pstatp.com/large/178100030f9ee4b453b1', 'has_video': False, 'title': '尴尬!默克尔访美被特朗普“甩脸” 握手请求遭无视'}, {'display_url': '/group/6398305109151138049/', 'media_url': 'http://toutiao.com/m5739097906', 'group_id': 6398305109151138049, 'has_image': True, 'image_url': 'http://p3.pstatp.com/origin/18a2000b7e1e6f9c3bab', 'has_video': False, 'title': '因材施教还是胡闹?细数分分钟刷三观的奇葩专业'}, {'display_url': '/group/6398869278900945153/', 'media_url': 'http://toutiao.com/m3232698963', 'group_id': 6398869278900945153, 'has_image': False, 'image_url': 'http://p3.pstatp.com/origin/18a1000d3cab1acc86b8', 'has_video': False, 'title': '贾静雯生下第三胎 前夫晒梧桐妹给自己的动人祝福'}, {'display_url': '/group/6398493215008538882/', 'media_url': 'http://toutiao.com/m6675759548', 'group_id': 6398493215008538882, 'has_image': True, 'image_url': 'http://p1.pstatp.com/origin/18a2000b7e76fded3cb3', 'has_video': False, 'title': '宏远力夺赛点 深圳功亏一篑'}]
>>> for new in data['data']['pc_feed_focus']:
print(new['title'], new['media_url'], new['image_url'])
秘鲁暴雨洪水肆虐已致75死 多座桥梁断裂 http://toutiao.com/m3232597584 http://p3.pstatp.com/origin/18a2000e3f19a682517d
农田内现8米“巨型西瓜” 原是瓜农休息屋 http://toutiao.com/m6159273532 http://p3.pstatp.com/origin/18a4000b2c3f020d2672
“抖森”和“大表哥”红毯相逢 一个玩合影一个高冷 http://toutiao.com/m6159077688 http://p3.pstatp.com/origin/18a3000e5352b8698692
女子冰壶世锦赛 中国队负捷克遭遇三连败 http://toutiao.com/m6159306637 http://p3.pstatp.com/origin/17810004879f0f1d5d58
面目全非的经典 无托雷明登步枪难畅销 http://toutiao.com/m3995104383 http://p1.pstatp.com/origin/18a5000e3a385dce3833
中国电影金扫帚奖颁奖典礼 柯震东得最佳男演员奖 http://toutiao.com/m6159077688 http://p3.pstatp.com/origin/17810004880274aa5f39
尴尬!默克尔访美被特朗普“甩脸” 握手请求遭无视 http://toutiao.com/m5784742177 http://p1.pstatp.com/large/178100030f9ee4b453b1
因材施教还是胡闹?细数分分钟刷三观的奇葩专业 http://toutiao.com/m5739097906 http://p3.pstatp.com/origin/18a2000b7e1e6f9c3bab
贾静雯生下第三胎 前夫晒梧桐妹给自己的动人祝福 http://toutiao.com/m3232698963 http://p3.pstatp.com/origin/18a1000d3cab1acc86b8
宏远力夺赛点 深圳功亏一篑 http://toutiao.com/m6675759548 http://p1.pstatp.com/origin/18a2000b7e76fded3cb3
总的代码就是这样了
import requests
import json
url = 'http://www.toutiao.com/api/pc/focus/'
html = requests.get(url)
web_data = html.text
data = json.loads(web_data)
for new in data['data']['pc_feed_focus']:
print(new['title'], new['media_url'], new['image_url'])
二、爬取今日头条美女图片
接着我们来爬爬头条的图片,在网页的右上角搜索下美女
像前面一样的步骤,先来分析下 xhr 响应,发现只有两个
先点开 hot_word 看看,先对这个 requests url 请求下看看
还是用上面的代码解析下
>>> import requests
>>> import json
>>> url = 'http://www.toutiao.com/hot_words/'
>>> html = requests.get(url)
>>> web_data = html.text
>>> data = json.loads(web_data)
>>> data
['老师教拼音引争议', '爬上山头脱衣轻生', '摆拍坠崖被批作死', '离异少妇骗大学生', '68万被摸10次脸', '全国取消药品加成', '陈赫前妻许婧出道', '蔡英文官邸遭突袭', '女富豪海选丈夫', '女儿趁母做饭跳楼']
发现这个 xhr 响应对应的是这个热门搜索。其实刚才直接点 priview 就能发现了,不过不要紧,多动动手也是极好的。
那么只剩下个 off... 什么的了,这次先点开 preview 看下,没错,就是我们想要图片的 json 请求数据了
这个请求头有提交内容,点开看看,keyword: 美女 这显然是咱们输入的关键词嘛。
那么 Requests URL 这个链接里 keyword 后面跟着的怎么是这个
%E7%BE%8E%E5%A5%B3
这是因为网址中的中文会被编码成UTF-8,每个中文3个字节,每个字节前加上%号。编码和解码方法如下:
>>> import urllib
>>> urllib.parse.unquote('%E7%BE%8E%E5%A5%B3')
'美女'
>>> urllib.parse.quote('美女')
'%E7%BE%8E%E5%A5%B3'
那么 url 链接里面的 count=20,是什么意思,点开priview 看看,上面有个 count:20 , cur_tab =1, 而 data 里面的数据刚好有20个,这显然就是图片的数量了
接着我们一直是在综合这个标签里,点击头条号,再看看 xhr 响应,最后的链接从刚的 1 变成了 4。那么这个 cur_tab 就是指搜素框下面的这四个选项了。
最后 url 中只剩下个 offset 了。
记得我们要爬取的是动态 js 网页么,我们可以发现网页图片是随着我们不断的下拉加载的,先下拉下看看。发现 xhr 响应多了一个了。
一看,跟我们上面的 url 链接并没多大差,只不过 offset 变成了 20 了。现在我们也知道了它的用处了把,就是随着20递进加载20张图片。
通过以上的分析,我们可以写出一个可以想要搜索任何关键词所对应的 json 所有请求网址了
>>> import urllib
>>> def build_urls(keyword):
url_keyword = urllib.parse.quote(keyword)
url = 'http://www.toutiao.com/search_content/?offset={page}&format=json&keyword={word}&autoload=true&count=20&cur_tab=1'
urls = (url.format(word=url_keyword, page=i) for i in range(0,1001,20)) #迭代50页先试试,以免有的关键词没有那么多页数的图片
return urls
接着我们来分析下 请求后返回的 json 格式的数据,找出我们想要的图片位置。
还是上面一样的方法,先爬一页分析看看。
>>> import requests
>>> url = 'http://www.toutiao.com/search_content/?offset=0&format=json&keyword=%E7%BE%8E%E5%A5%B3&autoload=true&count=20&cur_tab=1'
>>> r = requests.get(url)
>>> web_data = r.text
>>> import json
>>> data = json.loads(web_data)
>>>
注意这 data 内容太多了,我电脑的解释器并没有显示出来,那就在网页中分析下
可以看到我们想要的信息是存在 data 内的。 然后有个 article_url ,复制下链接在网页中打开,是图片所对应的网页链接,详细的图片都在里面。那么我们就可以在 data 里获取所有的 article_url ,再到每个对应的网页下载图片。
但是再仔细看下,有个 image_list ,打开一个链接看看,居然也是我们想要的图片,那么干脆在这里直接获取所有图片链接再下载。
来试试怎么找出图片链接。
>>> type(data['data'])
<class 'list'>
>>> type(data['data'][0])
<class 'dict'>
>>> data['data'][0]['image_list']
[{'url': 'http://p1.pstatp.com/list/190x124/18a3000e6a98dcefd804'}, {'url': 'http://p1.pstatp.com/list/190x124/18a4000b12f2b6b3fea0'}, {'url': 'http://p3.pstatp.com/list/190x124/18a2000e567b390f3a95'}]
>>>
发现图片链接居然是缩小的。再往下看,发现 image_detail ,里面的图片是正常的了。
>>> data['data'][0]['image_detail']
[{'uri': 'large/192100066bf00ee6f1a3', 'url': 'http://p9.pstatp.com/large/192100066bf00ee6f1a3', 'width': 580, 'url_list': [{'url': 'http://p9.pstatp.com/large/192100066bf00ee6f1a3'}, {'url': 'http://pb3.pstatp.com/large/192100066bf00ee6f1a3'}, {'url': 'http://pb3.pstatp.com/large/192100066bf00ee6f1a3'}], 'height': 387}, {'uri': 'large/191e00069d6c6f641ad6', 'url': 'http://p2.pstatp.com/large/191e00069d6c6f641ad6', 'width': 580, 'url_list': [{'url': 'http://p2.pstatp.com/large/191e00069d6c6f641ad6'}, {'url': 'http://pb3.pstatp.com/large/191e00069d6c6f641ad6'}, {'url': 'http://pb3.pstatp.com/large/191e00069d6c6f641ad6'}], 'height': 871}, {'uri': 'large/191f00068c87e1c917ed', 'url': 'http://p3.pstatp.com/large/191f00068c87e1c917ed', 'width': 1000, 'url_list': [{'url': 'http://p3.pstatp.com/large/191f00068c87e1c917ed'}, {'url': 'http://pb2.pstatp.com/large/191f00068c87e1c917ed'}, {'url': 'http://pb3.pstatp.com/large/191f00068c87e1c917ed'}], 'height': 1500}, {'uri': 'large/191d0000faae93e92f0e', 'url': 'http://p2.pstatp.com/large/191d0000faae93e92f0e', 'width': 750, 'url_list': [{'url': 'http://p2.pstatp.com/large/191d0000faae93e92f0e'}, {'url': 'http://pb3.pstatp.com/large/191d0000faae93e92f0e'}, {'url': 'http://pb3.pstatp.com/large/191d0000faae93e92f0e'}], 'height': 1125}, {'uri': 'large/191f00068d08b3fe1e96', 'url': 'http://p3.pstatp.com/large/191f00068d08b3fe1e96', 'width': 880, 'url_list': [{'url': 'http://p3.pstatp.com/large/191f00068d08b3fe1e96'}, {'url': 'http://pb2.pstatp.com/large/191f00068d08b3fe1e96'}, {'url': 'http://pb3.pstatp.com/large/191f00068d08b3fe1e96'}], 'height': 588}, {'uri': 'large/192000069e2c7a99c6c4', 'url': 'http://p3.pstatp.com/large/192000069e2c7a99c6c4', 'width': 750, 'url_list': [{'url': 'http://p3.pstatp.com/large/192000069e2c7a99c6c4'}, {'url': 'http://pb2.pstatp.com/large/192000069e2c7a99c6c4'}, {'url': 'http://pb3.pstatp.com/large/192000069e2c7a99c6c4'}], 'height': 426}, {'uri': 'large/191f00068daf3ac0b9a8', 'url': 'http://p9.pstatp.com/large/191f00068daf3ac0b9a8', 'width': 580, 'url_list': [{'url': 'http://p9.pstatp.com/large/191f00068daf3ac0b9a8'}, {'url': 'http://pb3.pstatp.com/large/191f00068daf3ac0b9a8'}, {'url': 'http://pb3.pstatp.com/large/191f00068daf3ac0b9a8'}], 'height': 386}]
>>>
把里面的 url 提取出来
>>> data['data'][0]['image_detail'][0]
{'uri': 'large/192100066bf00ee6f1a3', 'url': 'http://p9.pstatp.com/large/192100066bf00ee6f1a3', 'width': 580, 'url_list': [{'url': 'http://p9.pstatp.com/large/192100066bf00ee6f1a3'}, {'url': 'http://pb3.pstatp.com/large/192100066bf00ee6f1a3'}, {'url': 'http://pb3.pstatp.com/large/192100066bf00ee6f1a3'}], 'height': 387}
每个列表里面的链接都是重复的,提取 url 项里的就ok了
>>> data['data'][0]['image_detail'][0]['url']
'http://p9.pstatp.com/large/192100066bf00ee6f1a3'
综上,我们先迭代 data['data'] 这个列表里的 20 个项目,在迭代每一个 ['image_detail'] ,得到一个字典,最后获取该字典的 [‘url’] ,就可以得到我们想要的图片下载链接了。
对了,还有文章标题
>>> data['data'][0]['title']
'摄影:春夏秋冬,各式美女都齐了'
一样迭代 data['data'] 列表的20个项目,再获取对应的 ['title'], 就可以了。
综上,我们的步骤如下
(一)获取请求返回 json 数据的所有网址
(二)提取每个网址返回的数据的 title 及每个 title对应所有图片的下载链接
(三)下载图片
代码如下
import requests
import json
import urllib
import os
def build_urls(keyword):
url_keyword = urllib.parse.quote(keyword)
url = 'http://www.toutiao.com/search_content/?offset={page}&format=json&keyword={word}&autoload=true&count=20&cur_tab=1'
urls = (url.format(word=url_keyword, page=i) for i in range(0,100,20))
return urls
def get_link(i):
html = requests.get(i)
web_data = html.text
data = json.loads(web_data)
try:
for x in data['data']:
page = 1
a = os.getcwd()
title = x['title']
os.mkdir(title)
try:
for y in x['image_detail']:
picture = requests.get(y['url'])
if picture.status_code == 200:
path = a + '\\' + title + '\\'+ str(page) + '.jpg'
open(path, 'wb').write(picture.content)
page += 1
except KeyError:
print('Key image_detail error')
except KeyError:
print('Key title error')
def down_pic():
pass
if __name__ == '__main__':
a = input('请输入你想下载的头条图片\n')
links = build_urls(a)
for i in links:
get_link(i)
会报 key error 错误,因为这 json 格式请求太密密麻麻了,眼睛有点痛,就不查原因了,干脆写了 异常处理。试试看效果
还不错哈
就先这样啦