Ano*_*ous 6 request node.js web-scraping express
我正在尝试从 carjam.co.nz 中提取年份、品牌、型号、颜色和车牌号。我正在抓取的 URL 示例是https://www.carjam.co.nz/car/?plate=JKY242。
如果最近请求了牌照,则响应将是包含车辆详细信息的 HTML 文档。
如果最近没有请求车牌详细信息(大多数车牌都是这种情况),则响应是带有“尝试获取一些车辆数据”的 HTML 文档。我猜这个页面会在从数据库中获取信息时显示,然后重新加载页面以显示车辆详细信息。这似乎是在服务器端呈现的,我看不到任何 AJAX 请求。
每个结果的 URL 都相同。
我如何“等待”正确的信息?
我在request带有 Express 服务器的 Node.js 上使用(我知道已弃用,但这是我最习惯使用的)。
我的(非常减少的)代码:
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()),
}));
}
}
Run Code Online (Sandbox Code Playgroud)
我考虑过:
我确信这是一个常见问题,答案很简单,但我没有足够的经验来自己解决这个问题,或者确切地知道谷歌是什么!
测试:新西兰有“ABC123”格式的数字位置——三个字母,三个数字。这些是按字母顺序发布的,目前我们没有超过 NLU999 的内容(不包括自定义号牌、乱序发行的号牌等)。
要重现“试图获取一些车辆数据”,您每次都需要找到一个新的车牌——序列中早于 NLU999 的大多数车牌应该可以工作。
此代码段应生成有效的车牌。
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());Run Code Online (Sandbox Code Playgroud)
经过进一步思考,这个伪代码可能就是我所追求的——但不确定如何实际实现。
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)
Run Code Online (Sandbox Code Playgroud)
我的困难是:我习惯了格式request().then(),直接从请求中采取行动。
假设这种方法是正确的,我将如何进行以下操作?
From this javascript file, the website loads the page every X seconds if the data is not found with a max retry set to 10. Also the refresh value in seconds is retrieved from the Refresh http header value.
You can reproduce this flow, so that you have exactly the same behaviour as the frontend code.
In the following example I'm using axios
const axios = require("axios");
const cheerio = require("cheerio");
const rootUrl = "https://www.carjam.co.nz/car/";
const plate = "NLU975";
const maxRetry = 10;
const waitingString = "Waiting for a few more things";
async function getResult() {
return axios.get(rootUrl, {
params: {
plate: plate,
},
});
}
async function processRetry(result) {
const refreshSeconds = parseInt(result.headers["refresh"]);
var retryCount = 0;
while (retryCount < maxRetry) {
console.log(
`retry: ${retryCount} time, waiting for ${refreshSeconds} second(s)`
);
retryCount++;
await timeout(refreshSeconds * 1000);
result = await getResult();
if (!result.data.includes(waitingString)) {
break;
}
}
return result;
}
(async () => {
var result = await getResult();
if (result.data.includes(waitingString)) {
result = await processRetry(result);
}
const $ = cheerio.load(result.data);
console.log({
year: $("[data-key=year_of_manufacture]").next().html(),
make: $("[data-key=make]").next().html(),
model: $("[data-key=model]").next().html(),
colour: $("[data-key=main_colour]").next().html(),
});
})();
function timeout(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
Run Code Online (Sandbox Code Playgroud)
repl.it link: https://replit.com/@bertrandmartel/ScrapeCarJam
Sample output:
retry: 0 time, waiting for 1 second(s)
retry: 1 time, waiting for 1 second(s)
retry: 2 time, waiting for 1 second(s)
{ year: 'XXXX', make: 'XXXXXX', model: 'XX', colour: 'XXXX' }
Run Code Online (Sandbox Code Playgroud)
It uses async/await instead of promise.
Note that request is deprecated
| 归档时间: |
|
| 查看次数: |
83 次 |
| 最近记录: |