nodejs抓取动态网页(网络爬虫这块套路总结,用python+selenium执行代码上面第一种)

优采云 发布时间: 2022-01-02 12:06

  nodejs抓取动态网页(网络爬虫这块套路总结,用python+selenium执行代码上面第一种)

  我是北京一家互联网工厂的996程序员。一边学习追赶新技术,一边害怕被潮流甩在后面,一边学习投资理财的方法让自己的薪水滚雪球。我相信你越努力,你就越幸运。雪球虽然一开始滚得很慢,但只要你坚持住,它就会滚得越来越快,你的养老就靠它了。在财富和自由的道路上,我鼓励你。欢迎评论区和我交流经验和干货,让我们收获更多。

  我最近在抓一条网站的消息。今天写完了程序,用python+selenium。顺便总结一下网络爬虫的套路,分享给大家。

  

  方法一:直接接口调用。

  如果对方网站的api几乎没有反爬错误,那么可以直接通过浏览器的开发工具获取对方的api地址,直接调用爬取。如果对方界面控制了爬取频率,自己控制爬取间隔即可。

  如果使用python技术栈开发,使用requests库模拟接口调用。这里需要注意具体的headers,可能收录token、签名等,需要自己整理。

  方法二:使用js解析器执行js代码

  上面第一种情况提到的场景毕竟还是少数,大部分网站都采取了一些反爬虫的措施。比如网站通过页面加载的js向界面发起XHR类型的ajax请求。调用接口时,自定义参数添加到查询字符串或URL的头部,参数生成方法均在js中。 ,然后可以选择了解js代码,然后用python重写生成参数的代码,最后组装这些参数调用接口。

  但通常你没有那么幸运。生成参数的js代码比较混乱,基本无法被人类阅读。但是,如果你能定位到使用了哪个函数,那么我们可以采取另一种解决方案,就是将js代码改到js解释器中,然后直接调用函数获取返回值。我们拿这些返回值来组装请求参数。

  如果使用python技术栈开发,可以使用PyExecJS、PyV8、js2py、Node.js这些js解析器来运行js代码。

  js2py,一个纯python实现的js解析器,目前还在更新中。 PyExecJS,项目已经停止开发,但是还可以使用。 PyV8,是google v8 js引擎的python包。好久没更新了,不过还是可以用的。 Node.js,基于chrome v8引擎的js运行时,更新活跃。

  推荐使用 Js2py。

  方法三:使用selenium调用浏览器访问

  方法二的场景,js代码根本用不上,也无法定位到要用到哪些函数,所以只能搬出selenium。 Selenium 是一套工具包,通过它我们可以使用程序来控制浏览器访问目标网站。 Selenium 有很多语言的绑定,自然也有python 的绑定。

  使用selenium控制浏览器访问目标url后,如果要抓取的内容在页面内,则直接使用selenium提供的网页提取api直接提取内容。但是如果页面中没有渲染出你想要的内容,那我们就得用next方法了。

  方法四:使用selenium+proxy来抓取接口调用

  如方法3场景所述,对于js发起的ajax请求,如果响应数据没有完全反映在DOM中,那我们就得想办法直接提取ajax响应。方法是通过selenium+proxy控制浏览器访问,然后我们拦截proxy上的ajax响应。

  常用的代理是browsermob-proxy,是java开发的http/https代理。本方案的原则是

  在代码中控制启动browsermob-proxy。代码控制selenium启动浏览器,设置本地代理为browsermob-proxy。 Browsermob-proxy 会将请求的请求和响应写入 HAR 文件 (),我们可以通过解析 HAR 的内容得到响应。

  方法五:使用selenium+浏览器的性能日志

  这个方法可以认为是方法4的升级版,因为浏览器自己获取响应,所以只要找到合适的方法,就可以直接获取响应。

  具体方法是webdriver(python代码控制浏览器的一个组件)允许我们向浏览器发送Network.getResponseBody命令来获取响应。 webdriver 提供的 API 文档:

  

  我们需要传递一个名为 requestId 的参数来获取响应。

  首先,在初始化浏览器控件实例时,必须开启{"performance": "ALL"}

   def __init_driver(self):

capabilities = DesiredCapabilities.CHROME

capabilities["goog:loggingPrefs"] = {"performance": "ALL"} # chromedriver 75+

option = webdriver.ChromeOptions()

option.add_argument(r"user-data-dir=./var/chrome-data")

self.__driver = webdriver.Chrome(desired_capabilities=capabilities, options=option)

  然后

  def __scrape(self, url):

self.__driver.get(url)

time.sleep(3) # 等待页面中的请求完成

logs = self.__driver.get_log("performance")

  日志收录页面中的所有请求和响应。接下来,我们需要遍历每条数据,找到Network.responseReceived的类型,请求url就是我们要抓取的数据,从中获取requestId,然后就可以使用Network.getResponseBody来获取响应.

  def process_network_event(driver, logs, match_url):

for entry in logs:

message = json.loads(entry["message"]).get("message", {})

method = message.get("method", "")

is_method_match = method.startswith("Network.responseReceived")

if not is_method_match:

continue

url = message.get("params", {}).get("response", {}).get("url", "")

if url == "":

continue

if not url.startswith(match_url): # 匹配我们想要的url

continue

request_id = message.get("params", {}).get("requestId", "")

if request_id == "":

continue

try:

response_body = driver.execute_cdp_cmd('Network.getResponseBody', {'requestId': request_id})

except Exception as e:

print(f"getResponseBody by {request_id} failed: {e}, with message: {message}")

response_body = None

if not response_body:

continue

json_string = response_body.get("body", "")

if json_string == "":

continue

response = json.loads(json_string)

return response

  还有一个基于性能日志的python模块,可以更容易地提取请求和响应,[selenium-wire·PyPI](),[wkeeling/selenium-wire:扩展Selenium的Python绑定,让你能够检查浏览器发出的请求。]()。模块更新处于活动状态

  总结一下,方法五:在界面无法直接抓取的情况下,使用selenium+浏览器的性能日志是最好的解决方案。

  另外总结一下爬虫项目中的一些常用技巧

  UserAgent 应该稍微伪装一下,经常可以换不同的 UserAgent 来伪装不同的客户端。准备更多的代理。如果目标网站对IP有严格的控制,那么我们会经常更换代理。

  参考资料

  如果觉得我的分享对你有用,请关注并在评论区与我交流。我会继续分享一些有用的知识和经验。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线