【2023知乎爬虫】批量获取问题的全部回答

2023-11-04

一.需求

爬取任意问题下的所有回答,如下图:

1.根据问题,批量获取问题下的所有回答、与对应问题的关系到answer.csv文件;

2.保存当前问题基本信息到quesiton_info.csv文件;

二.展示爬取结果

三.讲解步骤

3.1 新建项目

本文使用scrapy分布式、多线程爬虫框架编写的高性能爬虫,因此新建、运行scrapy项目3步骤:

1.新建项目
scrapy startproject zhihu

2.新建 spider
scrapy genspider zhihu "zhihu.com"

3.运行 spider
scrapy crawl zhihuSpider

注意:zhihuSpider 是spider中的name

3.2 开发爬虫

F12,打开调试面板,经过调试后发现问题下的前5条回答数据不是通过接口返回的,第一页采用了服务端渲染的技术,第一页的数据在html的js中,如下图:

解析html中的内容使用bs4包,如下:

from bs4 import BeautifulSoup as bs

...

soup = bs(html, "html.parser")
# 拿到渲染HTML的json数据
initialData = soup.find("script", {"id": "js-initialData"}).get_text()
jsonData = json.loads(initialData)
# 解析出当前问题的基本信息,比如问题title,总回答数量、浏览量、关注人数、评论量...
current_questions = jsonData.get("initialState").get('entities').get(
    'questions')

`
把上面获取到的首页回答的数据整理出来就是第一页的回答内容啦;



编写item:

这里的字段就是要保存到csv文件的字段名称;

```py
class QuestionInfoItem(scrapy.Item):
    question_id = scrapy.Field()  # 问题ID
    question_name = scrapy.Field()  # 问题名称
    type = scrapy.Field()  # 问题类型
    question_url = scrapy.Field()  # 问题 url
    topics = scrapy.Field()  # 关键词
    follower_count = scrapy.Field()  # 关注者数
    visit_count = scrapy.Field()  # 被浏览数
    answer_count = scrapy.Field()  # 回答数
    comment_count = scrapy.Field()  # 评价数


class AnswerItem(scrapy.Item):
    question_id = scrapy.Field()  # 问题 ID
    answer_id = scrapy.Field()  # 问题 ID
    data_time = scrapy.Field()  #数据日期
    user_name = scrapy.Field()  # 账号昵称
    question_name = scrapy.Field()  # 问题名称
    content = scrapy.Field()  # 回答的内容
    voteup_count = scrapy.Field()  # 赞同数量
    comment_count = scrapy.Field()  # 评论数量
    created_time = scrapy.Field()  # 发布日期
    updated_time = scrapy.Field()  # 编辑日期
    answer_url = scrapy.Field()  # 回复 url

编写管道:


class QuestionInfoPipeline():

    def open_spider(self, spider):
        # 问题ID    问题名称	类型	关键词	关注者数	被浏览数	回答数  评价数
        self.question_info_line = "question_id,question_name,type,question_url,follower_count,visit_count,evaluate_score,comment_count\n"

        data_dir = os.path.join(DATA_URI)
        file_path = data_dir + '/question_info.csv'
        #判断文件夹存放的位置是否存在,不存在则新建文件夹
        if os.path.isfile(file_path):
            self.file = open(file_path, 'a+', encoding='utf-8')
        else:
            if not os.path.exists(data_dir):
                os.makedirs(data_dir)
            self.file = open(file_path, 'a+', encoding='utf-8')
            self.file.write(self.question_info_line)

    def close_spider(self, spider):  # 在关闭一个spider的时候自动运行
        self.file.close()

    def process_item(self, item, spider):
        try:
            if item['key'] == 'question':
                info = item.get('info')
                question_info_line = '{},{},{},{},{},{},{},{}\n'.format(
                    info.get('question_id', ''),  #问题ID
                    info.get('question_name', ''),  # 问题名称
                    info.get('type', ''),  # 问题类型
                    info.get('question_url', ''),  #问题 URL
                    info.get('follower_count', 0),  # 关注者数
                    info.get('visit_count', 0),  # 被浏览数
                    info.get('answer_count', 0),  # 回答数
                    info.get('comment_count', 0),  # 评价数
                )
                self.file.write(question_info_line)
        except BaseException as e:
            print("QuestionInfo错误在这里>>>>>>>>>>>>>", e, "<<<<<<<<<<<<<错误在这里")
        return item



...


编写爬虫解析代码:

def question_parse(self, response):
        html = response.text
        q_id = response.meta['q_id']
        soup = bs(html, "html.parser")
        # 拿到渲染HTML的json数据
        initialData = soup.find("script", {"id": "js-initialData"}).get_text()
        jsonData = json.loads(initialData)
        # 解析出当前问题的基本信息,比如问题title,总回答数量、浏览量、关注人数、评论量...
        current_questions = jsonData.get("initialState").get('entities').get(
            'questions')

        question_item = QuestionInfoItem()

        question = current_questions.get(q_id)

        question_item['question_id'] = q_id
        question_item['question_name'] = question['title']
        question_item['question_url'] = 'https://www.zhihu.com/question/%s' % (
            q_id)
        question_item['type'] = 'qeustion'
        question_item['follower_count'] = question['followerCount']
        question_item['visit_count'] = question['visitCount']
        question_item['answer_count'] = question['answerCount']
        question_item['comment_count'] = question['commentCount']

        yield {"key": 'question', "info": question_item}

        initialState = jsonData.get("initialState")
        # 解析出首页中回答的map
        ansers_map = initialState.get('entities').get('answers')

        # 解析出首页中回答出现的顺序
        answers = initialState.get('question').get('updatedAnswers')

        ansers_list = answers.get(q_id).get('newIds')

        # 根据回答顺序+回答map,把他俩组装成feed接口返回的报文格式
        first_page_result = tool.format_first_page_data(
            ansers_list, ansers_map, q_id)

        # 解析出首页中回答出现的顺序
        isEnd = initialState.get('commentManage').get('subCommentList').get(
            'paging').get('isEnd')
            
            
        ...

3.3 添加延时中间件

注意:多线程爬虫虽然每秒可并发16个请求,但是知乎服务器有反扒,太快会背关小黑屋,因此需要对请求作延时处理。

在中间件middlewares.py文件中添加如下中间件:

class RandomDelayMiddleware(object):

    def __init__(self, delay):
        self.delay = delay

    @classmethod
    def from_crawler(cls, crawler):
        delay = crawler.spider.settings.get("RANDOM_DELAY", 10)
        if not isinstance(delay, int):
            raise ValueError("RANDOM_DELAY need a int")
        return cls(delay)

    def process_request(self, request, spider):
        # 随机延时7-12s之间的3位小数结尾的时间,防止封号,务必添加
        delay = round(random.uniform(7, 12), 3)
        logging.debug("随机延时几秒: %ss" % delay)
        time.sleep(delay)

至此,本案例核心逻辑讲解完毕。完整代码包括: 翻页、保存csv、判断数据类型分类归类、x-zse-96加密文件、、、

3.4 完成项目说明手册:

四、获取完整源码

编码不易,请支持原创!

本案例完整源码及csv结果文件,付费后可获取↓

获取后,有任何代码问题,均负责讲解答疑,保证正常运行!

爱学习的小伙伴,本次案例的完整源码,已上传微信公众号“一个努力奔跑的snail”,后台回复**“知乎问答”**即可获取。

源码地址:

https://pan.baidu.com/s/1KoGg0tXE93vI8y4gzWeovg?pwd=****

提取码: ****

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【2023知乎爬虫】批量获取问题的全部回答 的相关文章

随机推荐

  • java 调用C#语言写的dll文件代码 超详细过程

    前言 最近在编写项目时候 遇到了java调用C 类库的情况 试了很多种方法 也遇到了很多坑 解决之后写下来 作为记录和分享给有用的朋友们 在这里我用的工具是jni4net 0 8 8 0 Visual Studio2015 一 编写C 类库
  • [人工智能AI]之贝叶斯网络

    人工智能AI 之贝叶斯网络 Bayesian network 部分图片和来源自 NJU 人工智能 高阳教授 的课件 通俗地讲 贝叶斯网络就是用一组有向无环图 表示多个事件的因果依赖关系 并借此完成相关推理计算 1 贝叶斯定理 条件概率 这里
  • linux服务器上部署多个vue项目(使用相同的ip(域名)及端口号)

    linux服务器上部署多个vue vue2 0 项目 使用相同的ip 域名 及端口号 1 首先想要实现的效果为 http ip 端口号 a 注 a代表a项目 http ip 端口号 b 注 b代表b项目 2 linux的文件路径为 3 此时
  • Qt迭代器(Java类型和STL类型)介绍

    一 介绍 遍历一个容器可以使用迭代器 iterators 来完成 迭代器提供了一个统一的方法来访问容器中的元素 而Qt的容器类提供了两种类型的迭代器 Java风格迭代器和STL风格迭代器 二 Java 类型迭代器 对于每个容器类 有两个 J
  • 【不定期更新-优化专题】

    文章目录 前言 一 学习资料类 前言 目前正在学习中 该专题主要用于分享自己的学习路线 工具 笔记等 欢迎交流与指正 一 学习资料类 视频 https www bilibili com video BV1Jt411p7jE 书籍下载 htt
  • VS:让程序运行完后不直接关闭

    Issue 控制台一闪而过 看不到输出结果 如何保持控制台窗口 让程序运行完后不直接关闭 Solve 1 推荐 建议设置项目属性 1 右键项目 gt gt 属性 Properties 打开项目的属性页 2 项目的属性页下 找到 配置属性 C
  • SQL语句优化问题

    有时返回数据时 需要有三张或以上的表需要查询 一张表的数据往往需要连接多张 效率非常的差 SELECT user id user uuid user user name AS username user login name name us
  • 测试项目:车牌检测,行人检测,红绿灯检测,人流检测,目标识别

    本项目为2020年中国软件杯 组第一批赛题 基于计算机视觉的交通场景智能应用 项目用python实现 主要使用YOLO模型实现道路目标如人 车 交通灯等物体的识别 使用开源的 中文车牌识别HyperLPR 项目实现车牌识别功能 github
  • OpenWRT UCI介绍及相关处理库

    OpenWRT UCI介绍及相关处理库 文章目录 OpenWRT UCI介绍及相关处理库 1 前言 2 概念 3 UCI配置文件 4 文件语法 5 命令行实用工具 5 1 用法 5 2 示例 导出整个配置 查看所有配置项的值 查看特定选项的
  • [Dotween] 介绍与使用,和坑

    Dotween 是在unity里实现各种动画效果 比如 位移 transform DoMove 旋转 transform DoRotation 缩放 transform DoScale 颜色改变 image DoColor 延时调用 Dov
  • QT中的QVariant类型-万能变量

    转自 https blog csdn net xiaopei yan article details 81410092 前言 QVariant这个类很神奇 或者说方便 很多时候 需要几种不同的数据类型需要传递 如果用结构体 又不大方便 容器
  • Vue前端自动化测试-Vue Test Utils

    Vue Test Utils简介 vue test utils是vue官方的单元测试框架 提供了一系列非常方便的工具 使我们更轻松地为vue构建的应用来编写单元测试 主流的JavaScript测试运行器有很多 但vue test utils
  • 中国人民大学和加拿大女王大学,学历的提升也是竞争力的提升

    如果想要读研提升自己在工作岗位上的竞争力和专业能力 报考在职研究生是一共非常不错的方式 在职研究生顾名思义就说国家计划内 以在职人员的身份 部分时间在职工作 部分时间在校学习的一种研究生类型 也是我国高等教育的重要组成部分 中国人民大学和加
  • 西洋经济史的趣味-赖建诚

    1990年代 台湾清华大学西洋经济史的老师 将的都是一些趣味性和严肃性的东西 明白一些经济学常识 1 经济学史到1993年 两个人获得诺贝尔经济学奖之后 才收到重视 2 这本书讲到了经济学史的重要性 3 火车轨道为什么是四尺八寸 因为这是国
  • web前端笔记

    web前端笔记 css选择器 标记选择器 如 div p 标签p id选择器 id class选择器 类名 通配符选择器 css文件外部链接 属性与属性之间用空格隔开 不是用逗号 HTML标签 双标签 p p 段落标签 标题标签 p h1
  • 微信开发 接口配置失败的坑新手注意

    申请的SAE 用来微信开发 填写完URL TOKEN后总会莫名其妙的爆出配置失败 如下的错误 出现这种原因有如下的原因 看你中招了没 1 最基本的检查这两个地方是否正确 怎么检查 不用我说吧 2 当发现上面的填写没问题 那就看这个你中招没
  • pandoc(markdown、latex、pdf、word相互转换的命令行工具)

    Markdown Pandoc 打通写作界的任督二脉 duqi yc的专栏 博客频道 CSDN NET http blog csdn net duqi yc article details 8974041 中文markdown转pdf Fl
  • java堆年轻代_Java堆(年轻代 -- 老年代 -- 永久代)

    JVM所管理的内存空间中 Java堆是最大的一块 主要用于存放各类实例对象 如下图 JVM中的堆被划分为两个不同区域 新生代Young 老年代Old 新生代又划分为Eden 伊甸 标志新生 Survivor0 s0 Survivor s1
  • 使用IDEA打包springcloud项目的jar包并发布至linux服务器

    前言 首先保证自己的springcloud项目在本地跑的通的 使用springcloud有可能缺少依赖的jar包 报 Java 程序包xxxx不存在 出现这种情况 因为配置Java的程序包这块出现了错误 同时可能你还没有设置让IDEA自动加
  • 【2023知乎爬虫】批量获取问题的全部回答

    一 需求 爬取任意问题下的所有回答 如下图 1 根据问题 批量获取问题下的所有回答 与对应问题的关系到answer csv文件 2 保存当前问题基本信息到quesiton info csv文件 二 展示爬取结果 三 讲解步骤 3 1 新建项