python爬虫——关于ajax加载之爬取2019年知乎问题和描述

本文介绍了使用Python爬取知乎数据的方法。需先写好带cookie的请求头并及时更新,打开开发者工具找到接口,观察到page_number和after_id变化规律。编写获取信息方法,分析接口数据获取问题标题、描述等,再写保存方法函数,最后附上完整代码,爬取数据会因判断和查重少于预期。

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()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值