使用BS4和Selenium实现高级网页数据采集的实战指南(爬取知乎数据)

最近因为一些原因,需要收集一些知乎的数据进行分析。但当实际操作时却发现遇到了种种问题.首当其冲的就是知乎的反爬机制.最初我的思路是先手动登录,然后提取并存放cookie信息到本地以方便以后使用.然后重新打开后再读取cookie然后刷新页面,结果遇到了和这篇博文一样的情况.

image.png

虽然能成功登录和访问问答,但当我获取搜索结果和点击展开评论时会报错. 经过一段时间的查阅和尝试后写下了这篇博客.

最初的思路:

不完整代码如下:

 

driver.get('https://www.zhihu.com')

# 暂停程序执行,等待一段时间(60秒),以确保网页加载完全

time.sleep(30)

# 获取当前页面的所有 cookie 信息,并将其存储为字典

dictCookies = driver.get_cookies()

# 将字典形式的 cookies 转换成 JSON 格式的字符串

jsonCookies = json.dumps(dictCookies)

print(jsonCookies)


# 将 JSON 格式的 cookies 写入到名为 "cookies_juejin.json" 的文件中

with open("cookies_zhihu.json", "w") as fp:

fp.write(jsonCookies)

# 关闭浏览器

driver.quit()


# 创建一个 Firefox 浏览器的实例

browser = webdriver.Firefox(options=options)



# 打开指定网页

browser.get("https://www.zhihu.com")

# 删除当前浏览器中的所有 cookie 信息

# browser.delete_all_cookies()

# 从名为 "cookies_juejin.json" 的文件中读取之前保存的 JSON 格式的 cookies

# with open('cookies_zhihu.json', 'r', encoding='utf-8') as f:

# listCookies = json.loads(f.read())

# # 将读取到的 cookies 添加到当前浏览器中

# for cookie in listCookies:

# browser.add_cookie(cookie)

# 再次访问网页,这次将包含之前保存的 cookie 信息,实现自动登录

browser.refresh()

使用Selenium来登录知乎,然后将获取到的cookies保存到一个JSON文件中,以便后续使用。在浏览器刷新时加载这些cookies,以实现自动登录。然而会遇到之前所说的那种问题,开始思考是哪里被发现了.

被发现的原因

经过查阅后发现, Selenium容易被检测的主要原因在于它所创建的浏览器指纹与手动操作所创建的浏览器指纹不同。一个常见的检测方法是通过检查window.navigator.webdriver这个关键字。在使用Selenium打开的浏览器中,该关键字的打印结果通常为true,而在正常手动操作的浏览器中,打印结果则为undefined。网站可以通过比较这些关键字的返回值来检测是否有自动化操作的迹象。这就是为什么Selenium容易被检测到的原因之一。

如何绕过

修改window.navigator.webdriver关键字返回结果.


options = webdriver.ChromeOptions()

# 此步骤很重要,设置为开发者模式,防止被各大网站识别出来使用了Selenium

driver = webdriver.Chrome(options=options)

# js注入,修改webdriver返还

driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {

'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'

})



driver.get('https://www.zhihu.com')

这段代码的关键点在于使用Chrome浏览器的开发者模式,同时通过CDP注入js,将navigator.webdriver的返回值修改为undefined。这样,网站在检测navigator.webdriver时会返回undefined,不再能够轻易检测到Selenium的使用。

然而,因为浏览器指纹很多,这种方法的局限性是显而易见的。不过配合手动登录,已经能获取服务器信任了.而是用cookie登录的话还是会出现之前的情况.

更多的应对机制

像之前提到的指令是在页面加载后执行js注入去修改特征,具有局限性,如果在修改之前网站就检查到该特征也还是会被发现。而参考:java - Selenium webdriver: Modifying navigator.webdriver flag to prevent selenium detection - Stack Overflow 有以下几条比较实用的方式:

  1. options.add_experimental_option("excludeSwitches", ["enable-automation"])

    • 通过add_experimental_option方法添加了一个名为"excludeSwitches"的选项,其值为一个包含"enable-automation"的列表。
    • 这个配置的目的是禁用Chrome中的"enable-automation"开关,这个开关通常用于检测自动化操作。
  2. options.add_experimental_option('useAutomationExtension', False)

    • 通过add_experimental_option方法添加了一个名为"useAutomationExtension"的选项,其值为False。
    • 这个配置用于禁用自动化扩展,这可以防止网站检测到Selenium的自动化操作。
  3. options.add_argument("disable-blink-features=AutomationControlled")

    • 通过add_argument方法添加了一个参数,其值为"disable-blink-features=AutomationControlled"。
    • 这个参数用于禁用Blink引擎中与自动化控制相关的特性,以进一步降低被检测为自动化爬虫的风险。
 

options = webdriver.ChromeOptions()

options.add_experimental_option("excludeSwitches", ["enable-automation"])

options.add_experimental_option('useAutomationExtension', False)

options.add_argument("disable-blink-features=AutomationControlled")

# 创建一个 Firefox 浏览器的实例

browser = webdriver.Chrome(options=options)

# 打开指定网页

browser.get("https://www.zhihu.com")

# 删除当前浏览器中的所有 cookie 信息

browser.delete_all_cookies()

# 从名为 "cookies_juejin.json" 的文件中读取之前保存的 JSON 格式的 cookies

with open('cookies_zhihu.json', 'r', encoding='utf-8') as f:

listCookies = json.loads(f.read())

# 将读取到的 cookies 添加到当前浏览器中

for cookie in listCookies:

browser.add_cookie(cookie)

# 再次访问网页,这次将包含之前保存的 cookie 信息,实现自动登录

browser.refresh()

或是直接通过cmd打开一个浏览器,再通过远程连接的方式去操作,这样无论打开多少个页面也不会被检测到.


# Author: 冷月半明

# Date: 2023/10/13

# Description: This script does XYZ.


from selenium import webdriver

from selenium.webdriver.common.by import By

from selenium.webdriver.support.ui import WebDriverWait

from selenium.webdriver.support import expected_conditions as EC

from selenium.webdriver.chrome.options import Options

import time

import json

from bs4 import BeautifulSoup


import subprocess


# 远程连接的方式建立浏览器实例

cmd = '"C:\Users\20976\AppData\Local\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="D:\code\Python大数据可视化\selenium_city\ChromeProfile"'

subprocess.run(cmd)

chrome_options = Options()

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

driver = webdriver.Chrome(options=chrome_options)


driver.get('https://www.zhihu.com')

cmd里第一个参数为浏览器可执行文件位置,第二个参数为占用端口,第三个参数为生成的数据文件存放位置.

自动化操作


def finddata():

input = driver.find_element(By.ID,'Popover1-toggle')

input.send_keys('南阳市旅游景点')

time.sleep(3)

element =driver.find_element(By.CLASS_NAME, 'Popover')

button= wait.until(EC.visibility_of_element_located((By.TAG_NAME, 'button')))

# element.click()

# = element.find_element(By., 'button')


button.click()

time.sleep(5)

首先查找了一个具有特定ID的输入框,然后在输入框中输入了文本。接着,它等待页面加载,查找了一个具有特定CLASS_NAME的元素,然后使用ExpectedConditions等待,确保一个按钮元素可见,并点击该按钮。

image.png

image.png

bs4提取数据


def gethtml():

# 获取网页源代码

page_source = driver.page_source

# 使用 BeautifulSoup 解析源代码

soup = BeautifulSoup(page_source, 'html.parser')

# print(soup)

# print(soup.select('.entry-list .item .entry .content-wrapper .content-main .title-row'))

for child in soup.select('.ListShortcut .css-0 .ContentItem-title'):

print(child.find('div').find('a')['href'],child.find('div').find('span').text)

首先使用driver.page_source获取网页的HTML源代码,然后使用BeautifulSoup库来解析HTML。它遍历了具有特定CSS选择器的元素。在循环中,代码使用.find()方法来查找特定元素,然后提取链接和文本信息,并将它们打印出来。

image.png

成果展示:

爬取到的url和标题.

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:【文末自行领取】

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值