简述:
考古加爬取高粉丝量达人数据,并存储到mongodb数据库。
网页链接:https://www.kaogujia.com/darenSquare/darenList
爬虫实现:
1.数据检索:F12进控制台找xhr接口,很惊喜的发现其中一个接口有大规模数据以及基于检索关键词的字符串(载荷)。
那么本次js逆向基于该接口展开,直接跟栈。跟进第一个匿名函数直接看到了另一个令人惊喜的关键字”send“以及"requestData"。题外话:一般跟栈很倾向于跟包含request或者send的方法,因此我们直接大胆跟进这个栈。
跟了一会儿可以看到data2就是我们响应中的数据内容,我们又可以注意到此处JSON.parse这个相当明显的解密关键词,因此我们宣布进入解密环节。
2.数据解密:我们执行完JSON.parse语句后,在console可以看到handleData就是明文数据。我们只需要扒下这行代码:
JSON.parse(decode(data2, response))
然后开始补环境。先补decode方法,观察一下代码,response是一个极其复杂的对象,我们不希望接触到它。很巧的是,我们尝试查看了url2,发现这是一个由两个元素组成的数组,其中第一个元素为"/api/author/search",第二个元素为"limit=50&page=1&sort_field=gmv&sort=0"。我们因此得以绕过response这个棘手的拦路虎。
decode = (data2,response)=>{
const url2 = response.config.url.split("?");
return decrypt(url2[0], data2)
}
我们还需要补充decrypt方法,这里我们已经解决了传入参数的问题,但仍存在两个问题:1.此处又遇到了一次decode方法的调用;2.为什么没有cryptoJs.exports这种调用方法呢?
const decrypt = function(url2, text2) {
if ("string" != typeof url2)
return;
const str = encode(url2).repeat(3)
, orgKey = str.slice(0, 16)
, orgIv = str.slice(12, 28)
, ikey = cryptoJs.exports.enc.Utf8.parse(orgKey)
, iiv = cryptoJs.exports.enc.Utf8.parse(orgIv);
return cryptoJs.exports.AES.decrypt(text2, ikey, {
iv: iiv,
mode: cryptoJs.exports.mode.CBC,
padding: cryptoJs.exports.pad.Pkcs7
}).toString(cryptoJs.exports.enc.Utf8)
};
我们先解决第二个问题,爬虫时经常使用的一个解密库便是crypto-js库,名字十分相似,我们直接调库能够达到完全一样的效果。实际上,源代码采取”cryptoJs.exports“的格式应该也是调库了。(源代码中有多处提及)
我们回到第一个问题,先补encode的环境,我们直接尝试就能正常读取到明文数据了。
function encode(str) {
const encode22 = encodeURI(str);
return btoa(encode22)
}
3.读入数据库:题外话:mongodb数据库并不是一个图形化界面很好的数据库,如果需要像excel一样直观看到数据库内容的还是建议sql。
import pymongo
myclient = pymongo.MongoClient("mongodb://localhost:27017/")
mydb = myclient["mydatabase"]
mycol = mydb["kaogu"]
# 删除全部数据
# mycol.delete_many({})
# 创建一个临时集合来存储结果
temp_col = mydb["users_temp"]
# 使用聚合管道和$out操作符来重写集合,排除重复的nickname
# 注意:这不会直接修改原始集合,而是将结果写入到一个新的集合中
pipeline = [
{"$group": {"_id": "$nickname", "first": {"$first": "$$ROOT"}}},
{"$replaceRoot": {"newRoot": "$first"}},
{"$out": "users_temp"}
]
# 执行聚合管道
mycol.aggregate(pipeline)
mycol.insert_many(page_data['items'])
for data in mycol.find({}, {'_id': 0, 'nick_name': 1, 'fans': 1}):
print(data)
这段代码演示了如何使用PyMongo来在MongoDB中处理数据,特别是如何删除重复项并重新插入数据。很有意思的一点是通过聚合管道将先前调试插入的大量数据进行分组并只保留第一个数据,完美的实现了大批量删除重复数据,下图展示部分结果。
附录给出聚合管道的技术特点:
-
聚合管道(Aggregation Pipeline):
- **group∗∗:这个阶段将数据按照‘nickname‘字段进行分组,并使用‘first
操作符保留每个组中的第一个文档。这有助于消除重复的
nickname`。 - **replaceRoot∗∗:这个阶段将‘group
阶段的结果的
first`字段作为新的根文档,这样每个文档的结构就与原始文档相同了,但只保留了每个昵称的第一个文档。 - $out: 这个阶段将聚合结果写入到新的集合中。在这里,结果被写入到名为"users_temp"的集合中。
Tips:如果你的nickname
字段不是唯一的,但你想要基于多个字段来确定唯一性,那么你可能需要调整聚合管道中的$group
阶段来包含额外的字段。
Tips^2:如果你要在重新插入数据之前清空原始集合,请使用mycol.delete_many()
来删除所有文档,或者使用mycol.drop()
来删除整个集合中的全部数据。
- **group∗∗:这个阶段将数据按照‘nickname‘字段进行分组,并使用‘first