Python中使用Scrapy爬取知乎内容,为什么获取的和原网页不一样?

新手刚开始学习. https://segmentfault.com/q/1010000008939688 这里有详细描述.谢谢.
Python中使用Scrapy爬取知乎内容,为什么获取的和原网页不一样?

16 回复

这是反爬策略吧


这个问题很常见,通常是因为知乎这类网站大量使用了JavaScript动态加载内容,而Scrapy默认只抓取初始的HTML静态页面。

简单说,你看到的“原网页”是浏览器执行了所有JS代码后的最终结果,而Scrapy拿到的是服务器最初返回的、还没被JS修改的“骨架”HTML。里面的很多数据(比如回答内容、评论)都是通过后续的AJAX请求加载的。

要解决这个问题,你有几个选择:

  1. 分析网络请求:用浏览器的开发者工具(F12 -> Network),找到实际加载数据的那个XHR/Fetch请求,直接用Scrapy去模拟请求那个API接口。这通常是最直接有效的方法。
  2. 使用Splash或Selenium:让Scrapy通过一个真正的浏览器(如Chrome)来渲染页面,拿到完整的DOM。但这会慢很多,资源消耗也大。
  3. 寻找隐藏数据:有时数据会以JSON格式藏在页面的<script>标签里,你可以用正则表达式或json模块把它提取出来。

核心建议:别爬页面,去爬它背后提供数据的API。

举个例子,假设你发现知乎某个问题页面的数据是通过一个像 https://www.zhihu.com/api/v4/questions/123456/answers?... 这样的接口返回的。你的Scrapy爬虫就可以直接请求这个URL:

import scrapy
import json

class ZhihuSpider(scrapy.Spider):
    name = 'zhihu'
    start_urls = ['https://www.zhihu.com/api/v4/questions/123456/answers?include=data[*].content&limit=20&offset=0']

    def parse(self, response):
        # 解析返回的JSON数据
        data = json.loads(response.text)
        for answer in data.get('data', []):
            # 提取你需要的信息,比如回答内容
            content = answer.get('content', '')
            # ... 处理或保存 content
            yield {'content': content}

        # 处理分页,如果存在的话
        if data.get('paging', {}).get('is_end') is False:
            next_page_url = data['paging']['next']
            yield scrapy.Request(url=next_page_url, callback=self.parse)

总结:直接去抓数据接口,别跟渲染后的页面较劲。

用到什么策略,可以详细说说吗?还有如何解决呢?谢谢.

你可以用 chromedrive 试试 如果还是不一样 那就说明确实有反爬的问题~

可能是页面异步获取了其他内容,所以直接抓取看不到,其中策略比较多

有问题可以加我们的群问,这样效率更高,这个群是一群工程师组建的面向初学者的 python Linux 学习群( qq 群号: 278529278 ) 非商业性质,拒绝广告,只接收真正想学这方面技术的朋友,交流学习,申请请说明来自 v2ex

好多异步请求

我也以为是异步,可是禁用 js 后的页面和我获取的页面还是不一样

好的,我试试..谢谢.

javascript ,

直接抓现成的 json 包,伪装客户端发包

你说的原网页是指的网页源代码还是审查元素?审查元素的代码是经过 js 渲染过的,不一样是很正常的,这个要以网页源代码的为标准,如果网页源代码和爬虫爬的不一样,另说,有可能是防爬。

网页源代码不一样...主要是一个 css 文件不一样,结果导致我写的 xpath 和 response.css 全部为空...这种是防爬吗?

应该是防爬了,防爬一般来就是根据 header 和 cookie 下文章,再有就是根据 ip 频率

不是防爬,还是 js 问题,我用 selenium+Phantomjs 成功解决.

如果是 js 问题,那么网页源代码和你抓取的应该是一样的,你用 Phantomjs ,还是因为有些 dom 是 js 动态生成的。

回到顶部