【发布时间】:2021-04-29 22:51:25
【问题描述】:
我正在尝试从 carjam.co.nz 中提取年份、品牌、型号、颜色和车牌号。我从中抓取的 URL 示例是 https://www.carjam.co.nz/car/?plate=JKY242。
如果最近请求过车牌,则响应将是包含车辆详细信息的 HTML 文档。
如果最近没有请求过车牌详细信息(大多数车牌都是这种情况),则响应是一个带有“尝试获取一些车辆数据”的 HTML 文档。我猜这个页面会在从数据库中获取信息时显示,然后重新加载页面以显示车辆详细信息。这似乎是在服务器端呈现的,我看不到任何 AJAX 请求。
每个结果的 URL 都是相同的。
我如何“等待”正确的信息?
我在带有 Express 服务器的 Node.js 上使用 request(我知道已弃用,但这是我最喜欢使用的)。
我的(非常精简的)代码:
app.get("/:numberPlate", (req, res) => {
request("https://www.carjam.co.nz/car/?plate=" + req.params.numberPlate, function(error, response, body) {
const $ = cheerio.load(body);
res.status(200).send(JSON.stringify({
year: $("[data-key=year_of_manufacture]").next().html(),
make: toTitleCase($("[data-key=make]").next().html()),
model: toTitleCase($("[data-key=model]").next().html()),
colour: toTitleCase($("[data-key=main_colour]").next().html()),
}));
}
}
我考虑过:
- 发出请求并将其丢弃,休眠 2 - 3 秒,然后发出第二个请求。这种方法的优点是每个请求都可以工作。缺点是每个请求都需要 2 - 3 秒(太慢)。
- 发出请求并检查正文是否包含“尝试获取某些车辆数据”。如果是这样,请休眠几秒钟,发出另一个请求并对第二个请求的结果采取行动(但如何?)。
我确信这是一个很容易回答的常见问题,但我没有足够的经验来自己弄清楚,或者确切地知道谷歌应该做什么!
测试:新西兰有“ABC123”格式的数字位置——三个字母,三个数字。这些是按字母顺序发布的,目前我们没有超过 NLU999(不包括自定义车牌、乱序发放的车牌等)。
要重现“尝试获取一些车辆数据”,您需要每次都找到一个新的车牌 - 序列中比 NLU999 更早的大多数车牌应该可以工作。
此代码 sn-p 应该会生成一个有效的车牌号。
console.log(Math.random().toString(36).replace(/[^a-n]+/g, '').substr(0, 1).toUpperCase() + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2).toUpperCase() + Math.floor(Math.random() * 10).toString() + Math.floor(Math.random() * 10).toString() + Math.floor(Math.random() * 10).toString());
2021 年 5 月 5 日更新
进一步思考,这个伪代码可能就是我所追求的——但不确定如何实际实现。
request(url) {
if (url body contains "Trying to get some vehicle data") {
wait(2 seconds)
request(url again) {
return second_result
}
} else {
return first_result
}
}
then
process(first_result or second_result)
我的困难:我习惯了request().then()的格式,直接从请求中采取行动。
假设这种方法是正确的,我将如何进行以下操作?
- 发送请求,然后
- 评估响应,然后
- 传递此响应,或发送另一个请求然后传递该响应
- 处理响应
【问题讨论】:
-
很高兴看到一个经过深思熟虑的综合问题 +
标签: node.js express web-scraping request