爬取zhi hu的小记录

在上篇制定了爬虫计划之后,我原本打算从zhi hu爬虫入手,因为同其他需要对多个目标站进行分析的任务相比,zhi hu的问答格式很统一,但后来发现原来自己跳了个大坑QQ。

目录

坑1:使用requests对zhi hu的搜索、问题页进行爬取

坑2:使用selenium对zhi hu的搜索页面进行爬取

坑2.1:将浏览器设置为开发者模式

坑2.2:手动开浏览器,然后程序接管

坑2.3:在没有运行Frame脚本前,提前设置window.navigator.webdriver值

坑2.4:中间人代理mitmproxy对response的相关字段进行替换

总结:


坑1:使用requests对zhi hu的搜索、问题页进行爬取

因为本次需要根据关键词对内容进行爬取,所以很容易想到对zhi hu的搜索页进行爬取。需要说明的是,从zhi hu的搜索页面和问题页面进行访问不是必须要登录的,所以登录这步可以绕过。

然而,zhi hu的问题页有一个绕不开的问题,那就是request的回答请求头中存在加密信息:x-zse-86,还有很长的cookie信息,在网上查找答案之后,发现这是今年zhi hu刚刚升级的反爬措施,需要对js进行逆向,过程很复杂,难以实现,而且网站的反爬措施是经常变化的,这样做并不能保证爬虫的长期有效。

因此,我决定牺牲一下效率,放弃requests,转而使用selenium模拟浏览器对页面渲染,爬取信息。

殊不知,到了这里,我又踏入了一个更大的坑……

坑2:使用selenium对zhi hu的搜索页面进行爬取

zhi hu的搜索页对selenium也是有反爬措施的,比如,当请求3个月内关键词为“电网”的内容时,我们手动浏览器打开是这样的:

但是使用selenium打开就变成了:

页面会自动隐藏正文内容。就算再次在搜素框中输入关键词,点击搜索,哪怕是手动,也永远会跳回这个页面。

此时使用的就是最常规的请求代码:

from selenium import webdriver
import urllib.parse  

br = webdriver.Chrome()
br.get("https://www.zhihu.com/search?q={}&type=content&range=3m".format(urllib.parse.quote('电网')))

urllib.parse.quote的作用是将字符串转化为url编码。

同样上网查找解决方法后,看来是需要隐藏selenium的自动化操作的身份。话说就算是自动化操作,浏览器渲染也够慢了,竟然还会被反爬……于是我又寻找了各路隐藏身份的办法,结果都没有用!下面列的都是对zhi hu没啥用的方法。

坑2.1:将浏览器设置为开发者模式

设置方法是这样的:

options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])   # 设置浏览器为开发者模式
br = webdriver.Chrome(options=options)

据说这样就隐藏了window.navigator.webdriver=True的信息,然鹅亲测无效。

坑2.2:手动开浏览器,然后程序接管

这个方法需要我们找到chrome.exe所在之处,或是将其加入环境变量,然后在命令行手动开启浏览器。

chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenum\AutomationProfile"

在指定端口运行chrome,并且使用单独的数据目录。这样手动开启浏览器后,使用程序接管:

options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")

这个办法虽然有些麻烦,真正自动化测试时需要脚本辅助,但看上去有点道理,然鹅,仍然是会被识别出来的。

坑2.3:在没有运行Frame脚本前,提前设置window.navigator.webdriver值

调用Google 的CDP(Chrome Devtools-Protocol),chrome开发工具协议。

br = webdriver.Chrome(options=options)
br.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
  "source": """
    Object.defineProperty(navigator, 'webdriver', {
      get: () => undefined
    })
  """
})

运行程序,在chrome的console中查询,发现window.navigator.webdriver确实不是true了:

但是,zhi hu一手好反爬,页面雷打不动没有正文,因此,我们很自然地想到,selenium可以被标识的字段不止一个,所以对这些字段都应该进行屏蔽。好的,机智的我又给自己挖了一个新坑。

坑2.4:中间人代理mitmproxy对response的相关字段进行替换

本方法参考了https://zhuanlan.zhihu.com/p/78368287中的内容,写了一个mproxy.py的脚本,与文中代码一致,一点小出入是启动程序时,把大写S改成小写s才成功执行。

不同的是,使用selenium打开chrome,走mitmproxy的默认端口8080作为代理:

options = webdriver.ChromeOptions()
PROXY='127.0.0.1:8080'
options.add_argument('--proxy-server={0}'.format(PROXY))  #  前面设置的端口号
options.add_argument('--ignore-certificate-errors')
br = webdriver.Chrome(options=options)

可以从命令行看出response中相关参数的确被移除了,但很不幸,这种方法仍然无效,我又尝试从zhi hu的js代码中搜索了一些可能会表明自动化程序的参数如_phantom,__phantomas等,但是仍然无效。

总结:

以上就是我在尝试爬取zhi hu搜索页面时踩到的所有坑坑,如果你也跟我一样并不是爬虫大神,那么希望这篇文章可以帮助你避一避坑。考虑到zhi hu的搜索页面其实并不完善,排序方式成谜且只能显示200多条信息,我决定放弃这种钻牛角尖式的方法,不去与反爬硬刚。zhi hu的单个问题详情页其实是对selenium很友好的,所以最终我选择通过“关键词+知乎”的方法从百度进行搜索,然后对结果中的单个问题页面进行爬取,除了速度慢一些,基本达到了预期效果。具体的爬虫设计方案将在下篇文章中介绍哦!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值