0-6范例总结(7)

0-6知识地图

7-1.png

知识地图说明:
之前接触的爬虫原理,在本质上是一个我们所操作的对象在不断转换的过程。
从Response对象开始就分成了两条路径:
一条路径是数据放在HTML里,用BeautifulSoup库去解析数据和提取数据;
另一条是数据作为Json存储起来,用response.json()方法去解析,然后提取、存储数据。

范例总结项目

爬取知乎大v的文章“标题”、“摘要”、“链接”

目标

获取文章“标题”、“摘要”、“链接”,并存储到本地文件。

分析与过程:

1、获取URL:https://www.zhihu.com/people/zhang-jia-wei/posts?page=1
2、shift+ctrl+i——Network,选All,然后刷新网页(F5)
3、点进去第0个请求:posts_by_votes(为方便理解和发现),点Preview。发现含有文章标题和格式一类的信息,看来数据是放在HTML里,那么,走的应该是【知识地图】里上面那条路径:
4、观察一下网页源代码,点回Elements
5、用ctrl+F验证和准确定位:
发现文章标题对应的就是元素里面的文本“大概,他们就是世上活得最明白的人吧。”还可以看到在标签里面,还有属性target="_blank",和data-za-detail-view-element_name="Title"。
此时使用页面搜索ctrl+F查看target的属性,发现共有105条记录之多,无法准确定位。而属性data-za-detail-view-element_name="Title",应该是知乎的开发人员自定义命名的,并不是html语法里标准的属性名。
向上观察和定位:的上一个层级是,并且有class="ContentItem-title"。用ctrl+f搜索“ContentItem-title”,发现这个属性有20个搜索结果,分别对应页面上的20篇文章,因此我们确认它可以帮我们精准定位目标数据。
6、写法思路:获取数据——用requests库;解析数据——用BeautifulSoup库;提取数据——用BeautifulSoup里的find_all();翻页的话观察第一页,到最后一页的网址特征,写循环;存储数据——用csv和openpyxl都可以。

代码实现

1、以一篇文章为例,逐步验证。
请求数据:“res=requests.get(url,headers=headers)”
然后验证一下:“print(res.status_code)”
显示200,继续。
2、可能遇到的问题:请求结果数据数量不足怎么办?
先来做个排查,使用 res.text 打印一下网页源代码。
如果发现源代码打印出来就是少的,有可能是我们选取的URL有问题。
返回去找完整数据。打开Network,点开XHR,同时刷新页面,看到出现了很多个请求。会发现第一个有article文件里的title不是文章的标题,而紧接着的第二个article里的title则与这一页的标题吻合。(第一个article是为了顺畅打开第二页而故意设计的,因为每一页内容都有20篇文章)所以,我们要到第二个article对应的Headers下General下的Request URL里找“?”前面的地址,作为我们的定位地址。
另外,通过观察第1页对第2页的请求,和第2页里对第3页请求的参数区别,是在headers里面的query string parameters里面。发现除了offset,其余都一样。offset代表起始值,limit表示加载的限制数,通过循环就可以爬到所有页数的内容了。因为有这个变量的存在,所以在请求头里要加入paramas的内容
3、此时解决问题的路径转入知识地图的第二条,用res.json()解析出数据。
4、根据json数据结构来提取我们想要的文章标题数据。
查看preview当中文章标题所在的结构位置。最外层是一个很大的字典,里面有两大元素,data:和paging:,这两大元素又是键值对应的字典形式,data这个键所对应的值是一个列表,里面有10元素,每个元素又是字典形式。

7-2.png

最外层是个字典。在键为data的值里面,又有一个列表。而列表的每个元素又是一个字典,在第0个元素的值里面,又有一个字典,这里面终于有了我们要拿的title: "国产航母下水……让我想到李鸿章和北洋舰队"。
5、取出想要的数据
data=articles['data'] #取出键为data的值。
for i in data:
print(i['title'])
print(i['url'])
print(i['excerpt']) #遍历列表,拿到的是列表里的每一个元素,这些元素都是字典,再通过键把值取出来
6、取出所有页码上的数据
第一页的数据我们就拿到后,接下来是要去拿所有页面的数据。经过上一步分析,第一页和第二页的请求参数区别在于offset,由此可以写一个循环。
7、如何结束这个循环?
第一页和最后一页请求的参数区别:两个页面的preview当中,第一页的is_end是显示false,最后一页的is_end是显示true,这个元素可以帮我们结束循环。
另外,还有一个totals: 919元素,应该是文章的总数,也同样可以作为结束循环的条件。两个元素都可以用。
8、为了不给网站过多压力,下载两页即停。
9、存储数据。
csv和openpyxl都可以做到,试试csv。
csv最主要的功能就是可以把列表按行写入。反推回来,也就是我们如果可以把数据写成list=[title,url,excerpt]的样子,那就可以直接写入啦。
写法如下:
import requests
import csv#引用csv。
csv_file=open('articles.csv','w',newline='',encoding='utf-8')#调用open()函数打开csv文件,传入参数:文件名“articles.csv”、写入模式“w”、newline=''、encoding='utf-8'。
writer = csv.writer(csv_file)# 用csv.writer()函数创建一个writer对象。
list2=['标题','链接','摘要']#创建一个列表
writer.writerow(list2)#调用writer对象的writerow()方法,可以在csv文件里写入一行文字 “标题”和“链接”和"摘要"。

headers={'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/XXX.XX (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/XXX.XX'}
url='https://www.zhihu.com/api/v4/members/zhang-jia-wei/articles?'
offset=0
#设置offset的起始值为0
while True:
params={
'include':'data[].comment_count,suggest_edit,is_normal,thumbnail_extra_info,thumbnail,can_comment,comment_permission,admin_closed_comment,content,voteup_count,created,updated,upvoted_followees,voting,review_info,is_labeled,label_info;data[].author.badge[?(type=best_answerer)].topics',
'offset':str(offset),
'limit':'20',
'sort_by':'voteups',
} #封装参数
res=requests.get(url,headers=headers,params=params) #发送请求,并把响应内容赋值到变量res里面
articles=res.json()
print(articles)
data=articles['data'] #定位数据
for i in data:
list1=[i['title'],i['url'],i['excerpt']] #把目标数据封装成一个列表
writer.writerow(list1) #调用writerow()方法,把列表list1的内容写入
offset=offset+20 #在while循环内部,offset的值每次增加20
if offset > 40:
break
csv_file.close()#写入完成后,关闭文件就大功告成
print('okay')

你可能感兴趣的:(0-6范例总结(7))