前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >AI新闻爬虫:传统爬虫和XHR异步加密爬虫的碰撞

AI新闻爬虫:传统爬虫和XHR异步加密爬虫的碰撞

原创
作者头像
叫我阿柒啊
发布2024-03-12 17:12:31
34400
代码可运行
发布2024-03-12 17:12:31
举报
运行总次数:0
代码可运行

前言

AI的发展日新月异,及时掌握一些AI的消息和妹子聊天时也不至于词穷(不建议和妹子聊技术)。

所以这里就以36氪和虎嗅网为例,来讲一下如何爬取AI新闻消息以及数据整合。36氪和虎嗅网这两个网站新闻爬虫比较具有代表性,36氪是传统的html网页爬虫,虎嗅网是异步api加载加密的爬虫,这里就从简单的36氪讲起。

36Kr

在36Kr通过搜索框输入AI,然后在快讯频道就可以看到最新的AI咨询。

对于判断爬取一个网站是使用传统html方式,还是异步加载的方式,最简单的方法就是“搜索”。根据从网页上看到的信息关键字进行搜索,来看看关键字出现在哪个请求中。

可以看到关键字出现在了html中,而不是xhr接口中,所以在36Kr获取最新的AI快讯就就是对HTML进行解析即可。接着看看HTML请求头信息,获取URL来获取HTML。

通过python的requests模块发起请求,最后解析目标数据实现36Kr AI快讯爬虫的代码开发。在python中,对html常用的解析方式有:BeautifulSoup和Xpath,因为之前写scrapy爬虫比较多,所以我个人比较喜欢使用scrapy.Selector,这里推荐大家用一下。

代码语言:python
代码运行次数:0
复制
import requests
from scrapy import Selector

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
}
url = 'https://36kr.com/search/newsflashes/AI'
response = requests.get(url, headers)
response = Selector(response)
articles = response.css('div.newsflash-item')
for article in articles:
    title = ''.join(article.css("a ::text").extract())
    url = 'https://36kr.com' + article.css("a::attr(href)").extract()[0]
    time = article.css("span.time::text").extract()[0]
    print(title, time, url)

Selector支持xpath和css语法,我这里使用的是css,这里只讲一个知识点:在获取title的哪行代码,通过a ::text获取a标签以及a标签下所有元素的文本内容。这里一定是有空格的,没有空格的话,只能获取a标签的文本。

最后解析了title、url、time三个字段,如果想爬取具体的新闻内容,可以在在for循环中对获取的url发起请求,在进行解析即可。

虎嗅网

虎嗅网同样也是在搜索框输入“AI”,搜索AI有关的资讯。在控制台通过搜索关键字,我们在xhr异步接口中发现了新闻咨询内容。

如图,新闻数据通过接口请求返回json的方式渲染的,而非36Kr返回的HTML,所以虎嗅网AI新闻咨询爬虫就是一个比较常见的XHR动态加载的爬虫。

查看请求头,分析请求需要的参数:

从platform到pagesize参数这里就不多讲了,appid是固定的。

有兴趣的可以打断点看看,这里主要讲讲nonce、timestamp、signature三个参数。

nonce、timestamp、signature

j(t) 方法中,可以看到nonce、timestamp、signature的构造过程。

nonce是调用 D() 方法生成的字符串,就是从A-Z|0-9|a-z中随机抽取16个字符。

代码语言:javascript
复制
function D() {
  for (var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 16, 
  e = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ", 
  n = "", i = 0; i < t; i++)
      n += e.charAt(Math.floor(Math.random() * e.length));
  return n
}

为了表现得更直观,打上了断点。

timestamp就是10位的时间戳,signature调用了一个 f 方法,参数是列表r。这个列表r是怎么来的呢?是将一个固定字符串n、timestamp、nonce放进去,然后进行排序,最后将三个元素拼接成一个字符串进行加密。

我们接着探究f():

t就是传进来的三合一的参数。然后就是密密麻麻的各种字节运算、位运算。正常情况下,是先将一行行js代码读懂,然后转换成python实现,最后返回signature。这就有点浪费时间了...

Don't Worry!!经常搞爬虫的朋友都知道,这其实就是个SHA-1加密,在python都是有现成的库...

所以

代码语言:python
代码运行次数:0
复制
import requests
import math
import random
import time
import hashlib
import json

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
    'Referer': 'https://www.huxiu.com/',
    'Origin': 'https://www.huxiu.com',
    'Content-Type': 'application/json'
}


def D():
    e = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    n = ""
    for i in range(0, 16):
        n += e[math.floor(random.random() * len(e))]
    return n


nonce = D()
timestamp = int(time.time())
n = 'hUzaABtNfDE-6UiyaYhfsmjW-8dnoyVc'
lists = [str(timestamp), str(n), str(nonce)]
lists.sort()
t = ''.join(lists)
hash_object = hashlib.sha1(t.encode())
signature = hash_object.hexdigest()
s = 'ai'
page = 1
pagesize = 20

url = f'https://search-api.huxiu.com/api/article?platform=www&s={s}&sort=&page=1&pagesize=20&appid=hx_search_202303&nonce={nonce}&timestamp={timestamp}&signature={signature}'
data = {
    'platform': 'www',
    's': s,
    'sort': '',
    'page': 1,
    'pagesize': 20,
    'appid': 'hx_search_202303',
    'nonce': nonce,
    'timestamp': timestamp,
    'signature': signature
}
response = requests.post(url, headers)
data = json.loads(response.text)
if data:
    datalist = data['data']['datalist']
    for article in datalist:
        title = article['title'].replace('</em>', '').replace('<em>', '')
        url = article['url']
        author = article['author']
        print(title, author, url)

signature直接使用hashlib库一行代码搞定,返回的是json格式的数据,使用json模块加载解析即可,最后输出三个字段:title、author、url。

问题排查

在程序测试的过程中,一直遇到“签名数据不正确”的响应数据。

遇到这个问题,我一共做了两步排查。

  1. 将程序中用户生成signature的参数粘贴到浏览器断点中测试,调用js生成的signature和程序程序中生成的一致,这说明我的程序代码逻辑是没问题的。
  2. 我从浏览器控制台复制了url,使用http客户端进行测试,最后也能请求到数据,说明接口也是没问题的。

于是,我就迷茫了。后来又打了一次断点,发现n这个变量发生了错误,在代码中,你可以看到我使用的是'hUzaABtNfDE-6UiyaYhfsmjW-8dnoyVc'。

其实这个n的初始值是'w-Ui'结尾的,后面又计算赋值修改了其他值,我程序中刚开始用的就是初始值,所以虽然signature生成逻辑没有错,但是参数错了。

结语

这就是我使用爬虫爬取AI新闻的过程,使用了两个爬虫中比较常见的典型案例。像这种类别信息的采集,还有更优的程序设计架构。

上面的程序没有设计存储模块,如果设计了采集模块,且采集了许多网站的AI新闻消息的话,我建议使用scrapy的架构做一个统一的管理,包括程序、存储模块、并发、参数等等的统一管理,架构图放下面,有兴趣的可以了解一下。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 36Kr
  • 虎嗅网
    • nonce、timestamp、signature
      • 问题排查
      • 结语
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
      http://www.vxiaotou.com