我正在学习使用JavaScript进行网络抓取,当try 登录到控制台一个简单的网页时,我遇到了一个奇怪的404错误:

加载资源失败:服务器响应状态为404 (未找到)拒绝执行来自"[.]的脚本 playbook "因为它 SME类型("text/html")不可执行,并且是严格的SME类型 已启用判断.

我怀疑第二个错误只是await axios.get(url)无法正常工作的失败的副作用.

我的代码:

import { load } from "cheerio";
import axios from "axios";

const testGet = async function (url) {
  try {
    const response = await axios.get(url);
    const html = response.data;
    const $ = load(html);
    console.log($.html());
  } catch (error) {
    console.error(error);
  }
};

const url = "https://books.toscrape.com";
testGet(url);

请注意,我当然可以使用普通网络浏览器访问https://books.toscrape.com的内容.

已经确保我的Package.json列出了axios和Cheerio,如下所示:

{
  "type": "module",
  "dependencies": {
    "axios": "^1.6.8",
    "cheerio": "^1.0.0-rc.12"
  }
}

node -v:

v18.17.1

多次重新启动实时服务器,在CoPilot和chatGPT的帮助下判断拼写错误,但没有发现任何问题.

重新安装了cheerio并手动将""类型":"模块"添加到Package.json文件中,因此现在该脚本在带有node .\script.js的终端中直接运行时可以按预期工作,但在live-server中运行时仍然不工作.

推荐答案

根据 comments 中的讨论,您正在try 从GitHub Pages上托管的网站运行抓取代码.问题是,大多数抓取都发生在后台,其中请求不会被CORS阻止.CORS是一种服务器端限制,用于防止网站向其他来源发出请求.

try 以下代码,这足以说明问题:

fetch("https://books.toscrape.com").catch(err => console.error(err));

您应该在浏览器开发工具控制台中看到以下内容:

Cross-Origin Request Blocked:
The Same Origin Policy disallows reading the remote resource at https://books.toscrape.com/.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.

...但 node 中没有错误.

您处理此问题的 Select 包括:

  1. 托管一个可以为您代理请求的服务器.GH Pages没有后台,但您可以使用在确实支持后台(例如glitch)的网站上运行的Express来实现这一点.您可以使用现有的Axios + Cheerio代码发出请求并提取Express路由中想要的数据,然后将抓取的数据返回到前端仪表板.您的Express服务器将明确允许来自您的GH页面域的请求跨源setting the access control HTTP header:

    res.setHeader("Access-Control-Allow-Origin", "https://yourname.github.io");
    
  2. 使用GitHub Action运行抓取代码并将数据写入GitHub仓库中的静态文件.如果数据不经常变化,这是一个很好的技术--您可以每天或每周运行您的操作.有关如何设置此功能的演练,请参阅this blog post.

  3. 使用cors-anywhere代理请求,而无需托管您自己的后台.您可以使用cors-anywhere演示服务器进行测试,但从长远来看,您应该托管自己的实例,您可以在Render.com

fetch("https://cors-anywhere.herokuapp.com/" + "https://books.toscrape.com")
  .then(response => response.text())
  .then(text => {
    const doc = new DOMParser().parseFromString(text, "text/html");
    const title = doc.querySelector("title").textContent.trim();
    console.log(title);
  })
  .catch(err => console.error(err));

为了使此代码片段有效,您需要转到http://cors-anywhere.herokuapp.com/corsdemo并单击按钮才能获得临时访问权限.

请注意,实际上并不需要在前端使用axios和cheerio,只需在后台使用即可.前端已经拥有fetch、jQuery和原生多姆解析器.Cheerio是jQuery到 node 的移植,因此将其带回浏览器没有意义.Axios需要加载才能在浏览器中使用,因此它提供的轻微语法简单性无法与原生获取相媲美.

Javascript相关问答推荐

成帧器运动中的运动组件为何以收件箱开始?

GrapeJS -如何保存和加载自定义页面

togglePopover()不打开但不关闭原生HTML popover'

从WooCommerce Checkout Country字段重新排序国家,保持国家同步

Snowflake JavaScript存储过程返回成功,尽管预期失败

使用JQuery单击元素从新弹出窗口获取值

我的角模板订阅后不刷新'

如何在coCos2d-x中更正此错误

如何在Svelte中从一个codec函数中调用error()?

try 使用PM2在AWS ubuntu服务器上运行 node 进程时出错

如何在FastAPI中为通过file:/URL加载的本地HTML文件启用CORS?

为什么我的按钮没有从&q;1更改为&q;X&q;?

回溯替代方式

为什么当我更新数据库时,我的所有组件都重新呈现?

当我点击一个按钮后按回车键时,如何阻止它再次被点击

顶点图使用组标签更新列之间的条宽

P5play SecurityError:无法从';窗口';读取命名属性';Add';:阻止具有源的帧访问跨源帧

Refine.dev从不同的表取多条记录

通过ng-绑定-html使用插入的HTML中的函数

错误400:当我试图在React中使用put方法时,该字段是必需的