python爬虫——关于ajax加载之爬取2019年知乎问题和描述
1.先放上效果图(描述为空的原因是本来就没写描述或者只放了图片被我去掉了).
2.知乎网址https://www.zhihu.com/
3.先写好请求头(知乎是需要登录才能看的,所以一定要写cookie,而且要过几天cookie就会过期,一定要记得更新,老夫就是栽在这上面耽误了好久)
#请求头
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36',
'Referer':'https://www.zhihu.com/',
'Cookie':'自行设置'
}
4.打开开发者工具下滑让网页加载的多一点,找到接口并观察规律
5.发现只有page_number和after_id变化了,看接口里的数据,都是每个接口6条数据,所以每次加载6条数据,page_number记录加载次数,after_id记录是第几条数据
6.写一个获取知乎网址信息的方法
#获取知乎接口网址的数据
def get_page(page_number):
params = {
'session_token':'4975ba96688e66562b3a4d2d4cfa5185',
'desktop':'true',
'page_number':page_number,#地址中有2个变量page_number和after_id,但这2个数据有关联
'limit':'6',
'action':'down',
'after_id':int(page_number)*6-7
}
base_url = 'https://www.zhihu.com/api/v3/feed/topstory/recommend?'
#接口网址的前边地址
url = base_url + urlencode(params)#拼接地址
try:
resp = requests.get(url,headers = headers)
print(url)
if 200 == resp.status_code:
return resp.json()#如果能访问到以json类型返回
except requests.ConnectionError:
return None
7.分析一下接口的数据,所有数据在data下,created是创建时间,去时间戳上转化一下,这个时间是2019/4/19 0:13:19,title 是问题标题,excerpt是问题描述,但是这里拿到的问题描述是不全的,多的会省略,所以我通过id再去访问这个问题,获取完整的问题描述
#抽取信息
def get_data(json):
if json.get('data'):
items = json.get('data') # 定位到data那一栏
for item in items: # 遍历items,获取0-5下的数据
item = item.get('target').get('question')#定位到问题那一栏
if item:#先判断能不能拿到item
try:
if(item.get('created')):#知乎问题创建时间
time = item.get('created')
if time>1546272000:#时间戳 判断是否是在2019年的
titles = item.get('title')#知乎问题标题
question_id = item.get('id')#知乎问题id
url = "https://www.zhihu.com/question/" + str(question_id)
#为了拿到完整的描述需要访问问题的网页,
response = requests.get(url, headers=headers)
html = etree.HTML(response.text)#用xpath获取网页信息
excerpts = html.xpath('//span[@class="RichText ztext"]/text()')
#获取到完整的知乎问题描述
excerpts = ''.join(excerpts)#将list转化为字符串
excerpts = re.sub(r'\[图片\]|本题.*?再见初代复联','',excerpts)
#将图片和最近很火的复联知乎圆桌清洗掉
data_dict = {}#写入字典
data_dict['titles']=titles
data_dict['excerpts']=excerpts
if(data_dict not in data_list):#查重,如果没重复就加入
data_list.append(data_dict)
else:
continue#如果不在2019年就跳过
except requests.ConnectionError:
return None
return True
else:
return None
8.能获取到数据那么后面就简单了,写保存方法的函数
def save_data():
#写入json文件
content = json.dumps(data_list,ensure_ascii=False,indent=2)
#字典转化为json,有中文要加ensure_ascii=False
with open("zhihu.json", "a+", encoding="utf-8") as f:
f.write(content)
print("正在保存:"+content)
# 将数据写入csv文件
with open('data_csv.csv', 'w', encoding='utf-8', newline='') as f:
# 表头
title = data_list[0].keys()
# 声明writer
writer = csv.DictWriter(f, title)
# 写入表头
writer.writeheader()
# 批量写入数据
writer.writerows(data_list)
9.最后调用这些函数就行了
def main():
page_number = 1#初始设置为1
while True:
json = get_page(page_number)#调用获取接口的方法
flag = get_data(json)#调用获取数据的方法
page_number += 1
if(page_number>=21):#自增,当大于等于21时中止,我为了偷懒就少爬一些
break
save_data()#调用存储的方法
if __name__ == '__main__':
main()
10.附上完整代码,因为判断的是否是2019的问题和查重,所以爬取到的数据条数是远远小于6*20条的
import requests
from urllib.parse import urlencode
from lxml import etree
import re
import json
import csv
#声明一个全局变量存储字典
data_list = []
#请求头
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36',
'Referer':'https://www.zhihu.com/',
'Cookie':'自行设置'
###############################################################################一定要设置啊
###############################################################################一定要设置啊
###############################################################################一定要设置啊
}
#获取知乎网址
def get_page(page_number):
params = {
'session_token':'4975ba96688e66562b3a4d2d4cfa5185',
'desktop':'true',
'page_number':page_number,#地址中有2个变量page_number和after_id,但这2个数据有关联
'limit':'6',
'action':'down',
'after_id':int(page_number)*6-7
}
base_url = 'https://www.zhihu.com/api/v3/feed/topstory/recommend?'
#接口网址的前边地址
url = base_url + urlencode(params)#拼接地址
try:
resp = requests.get(url,headers = headers)
print(url)
if 200 == resp.status_code:
return resp.json()#如果能访问到以json类型返回
except requests.ConnectionError:
return None
#抽取信息
def get_data(json):
if json.get('data'):
items = json.get('data') # 定位到data那一栏
for item in items: # 遍历items,获取0-5下的数据
item = item.get('target').get('question')#定位到问题那一栏
if item:#先判断能不能拿到item
try:
if(item.get('created')):#知乎问题创建时间
time = item.get('created')
if time>1546272000:#时间戳 判断是否是在2019年的
titles = item.get('title')#知乎问题标题
question_id = item.get('id')#知乎问题id
url = "https://www.zhihu.com/question/" + str(question_id)
#为了拿到完整的描述需要访问问题的网页,
response = requests.get(url, headers=headers)
html = etree.HTML(response.text)#用xpath获取网页信息
excerpts = html.xpath('//span[@class="RichText ztext"]/text()')
#获取到完整的知乎问题描述
excerpts = ''.join(excerpts)#将list转化为字符串
excerpts = re.sub(r'\[图片\]|本题.*?再见初代复联','',excerpts)
#将图片和最近很火的复联知乎圆桌清洗掉
data_dict = {}#写入字典
data_dict['titles']=titles
data_dict['excerpts']=excerpts
if(data_dict not in data_list):#查重,如果没重复就加入
data_list.append(data_dict)
#这里我是将数据全部放入data_list然后再一起存储的,并用它判断是否重复
else:
continue#如果不在2019年就跳过
except requests.ConnectionError:
return None
return True
else:
return None
def save_data():
#写入json文件
content = json.dumps(data_list,ensure_ascii=False,indent=2)
#字典转化为json,有中文要加ensure_ascii=False
with open("zhihu.json", "a+", encoding="utf-8") as f:
f.write(content)
print("正在保存:"+content)
# 将数据写入csv文件
with open('data_csv.csv', 'w', encoding='utf-8', newline='') as f:
# 表头
title = data_list[0].keys()
# 声明writer
writer = csv.DictWriter(f, title)
# 写入表头
writer.writeheader()
# 批量写入数据
writer.writerows(data_list)
def main():
page_number = 0
while True:
json = get_page(page_number)
flag = get_data(json)
page_number += 1
if(page_number>=5):#自增,当大于等于20时中止
break
save_data()
if __name__ == '__main__':
main()