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

前言

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,这里推荐大家用一下。

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个字符。

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都是有现成的库…

所以

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的架构做一个统一的管理,包括程序、存储模块、并发、参数等等的统一管理,架构图放下面,有兴趣的可以了解一下。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值