常见的爬取请求有node-fetch、axios或got

Common crawl request with node-fetch, axios or got

我正在尝试将我的 C# 通用抓取代码移植到 Node.js,但在从 HTML 获取单个页面时,所有 HTTP 库(node-fetch、got 的 axios)都出现错误共同抓取 S3 存档。

const offset = 994879995;
  const length = 27549;
  const offsetEnd = offset + length + 1;
  const url = `https://data.commoncrawl.org/crawl-data/CC-MAIN-2018-43/segments/1539583511703.70/warc/CC-MAIN-20181018042951-20181018064451-00103.warc.gz`;
  const response = await fetch(
    url, //'https://httpbin.org/get',
    {
      method: "GET",
      timeout: 10000,
      compress: true,
      headers: {
        Range: `bytes=${offset}-${offsetEnd}"`,
        'Accept-Encoding': 'gzip'
      },
    }
  );

  console.log(`status`, response.status);
  console.log(`headers`, response.headers);
  console.log(await response.text());

状态为 200,但包的 none 能够读取正文 gzip 正文。

虽然我的 C# 代码可以正常读取正文作为字节数组并将其解压缩。

下面的代码将获取单个 WARC 记录并提取 HTML 有效负载。所有状态行和 headers(WARC 记录的 HTTP 提取、WARC 记录 header、WARC 记录 HTTP header)以及 HTML 有效负载都会被记录下来。更改了以下几点:

  • JS请求中的范围header包含多余的引号。这实际上导致请求的不是单个 WARC 记录,而是完整的 1+ GiB WARC 文件。

    • 查看响应状态代码:200 但应为 206“部分内容”
    • 还有“content-length”响应 header
    • 对于获取 1 GiB,10 秒的超时时间可能太短
  • 结束偏移量应该是offset + length - 1(而不是... + 1):在最坏的情况下,2个额外的字节会导致gzip解压器抛出异常

  • 因为 WARC 记录已经 gzip-compressed 请求任何 HTTP-level 压缩没有意义

  • gzipped WARC 记录需要解压缩和解析。两者都是由 warcio 完成的 - 看看这个模块的优秀文档。

const fetch = require("node-fetch");
const warcio = require("warcio");

class WarcRecordFetcher {

    async run() {
        const offset = 994879995;
        const length = 27549;
        const offsetEnd = offset + length - 1;
        const url = `https://data.commoncrawl.org/crawl-data/CC-MAIN-2018-43/segments/1539583511703.70/warc/CC-MAIN-20181018042951-20181018064451-00103.warc.gz`;

        const response = await fetch(
            url, //'https://httpbin.org/get',
            {
                method: "GET",
                timeout: 10000,
                headers: {
                    Range: `bytes=${offset}-${offsetEnd}`
                },
            }
        );

        console.log(`status`, response.status);
        console.log(`headers`, response.headers);

        const warcParser = new warcio.WARCParser(response.body);
        const warcRecord = await warcParser.parse();

        console.log(warcRecord.warcHeaders.statusline);
        console.log(warcRecord.warcHeaders.headers);

        console.log(warcRecord.httpHeaders.statusline);
        console.log(warcRecord.httpHeaders.headers);

        const warcPayload = await warcRecord.contentText();
        console.log(warcPayload)
    }

}

new WarcRecordFetcher().run();