You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在无API情况下用Node.js获取Quizlet学习集数据

问题:爬取Quizlet学习集遭遇403拦截,请求解决方案

我想用Quizlet的学习集做项目,但官方API已经停了很久。找替代API的过程中全是误导信息:有人说旧API还能用但需要没法生成的access token,也有人说旧API彻底失效了。所以我决定不碰API,直接抓HTML提取卡片数据。试了quizlet-fetch和quizlet-fetcher两个包都不好使,实际操作比想象中难,Quizlet一直在拦截请求,反复出现Request failed with status code 403错误。以下是我目前的代码,求相关建议:

const express = require('express');
const app = express();
const axios = require('axios');
const cheerio = require('cheerio');
const https = require('https');
const httpProxy = require('http-proxy');

const proxy = httpProxy.createProxyServer();

// Proxy server
proxy.on('error', function(err, req, res) {
  console.error(err);
  res.writeHead(500, {
    'Content-Type': 'text/plain'
  });
  res.end('Error');
});

// Allow all origins to access this API
app.use(function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

// Fetch the HTML for a Quizlet set
const fetchQuizletSet = async (url) => {
  const config = {
    headers: {
      'Content-Type': 'text/html',
    },
    httpsAgent: new https.Agent({
      rejectUnauthorized: false
    })
  };
  const response = await axios.get(url, config);
  return response.data;
};

// Parse the HTML for a Quizlet set and extract the card data
const parseQuizletSet = (html) => {
  const $ = cheerio.load(html);
  const title = $("h1.PageTitle-heading").text().trim();
  const cards = [];
  $(".SetPageTerms-term").each((index, element) => {
    const front = $(element).find(".SetPageTerm-wordText").text().trim();
    const back = $(element).find(".SetPageTerm-definitionText").text().trim();
    const image = $(element).find(".SetPageTerm-media img").attr("src");
    const audio = $(element)
      .find(".SetPageTerm-media audio source")
      .attr("src");
    cards.push({ front, back, image, audio });
  });
  return { title, cards };
};

// Define a route to handle Quizlet set requests
app.get('/quizlet-set/:setId', async (req, res) => {
  const setId = req.params.setId;
  const url = `https://quizlet.com/${setId}`;
  try {
    const html = await fetchQuizletSet(url);
    const data = parseQuizletSet(html);
    res.json(data);
  } catch (error) {
    console.log(error);
    res.status(500).send(error.message);
  }
});

// Start the server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
});

解决方案建议

1. 完善请求头,模拟真实浏览器请求

Quizlet的反爬机制会识别非浏览器发起的请求,当前请求头过于简单,需添加常见浏览器标识:
修改fetchQuizletSet函数的headers配置:

const fetchQuizletSet = async (url) => {
  const config = {
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
      'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
      'Accept-Language': 'en-US,en;q=0.5',
      'Accept-Encoding': 'gzip, deflate, br',
      'Connection': 'keep-alive',
      'Upgrade-Insecure-Requests': '1'
    },
    httpsAgent: new https.Agent({
      rejectUnauthorized: false
    })
  };
  const response = await axios.get(url, config);
  return response.data;
};

2. 处理动态渲染内容

现在Quizlet多数页面内容通过JavaScript动态加载,直接抓取HTML可能无法获取完整卡片数据。可改用puppeteer无头浏览器工具,模拟真实浏览器加载页面后再抓取:
先安装依赖:

npm install puppeteer

再修改fetchQuizletSet函数:

const puppeteer = require('puppeteer');

const fetchQuizletSet = async (url) => {
  const browser = await puppeteer.launch({ headless: 'new' });
  const page = await browser.newPage();
  await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36');
  await page.goto(url, { waitUntil: 'networkidle2' }); // 等待网络空闲,确保内容加载完成
  
  const html = await page.content();
  await browser.close();
  return html;
};

3. 添加请求延迟与重试机制

频繁请求会触发反爬限制,给请求添加随机延迟,同时在遇到403时自动重试:

const fetchQuizletSet = async (url, retries = 3) => {
  try {
    // 添加随机延迟,避免请求过于频繁
    await new Promise(resolve => setTimeout(resolve, Math.random() * 1000 + 500));
    
    const config = {
      headers: {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
        'Accept-Language': 'en-US,en;q=0.5',
        'Accept-Encoding': 'gzip, deflate, br',
        'Connection': 'keep-alive',
        'Upgrade-Insecure-Requests': '1'
      },
      httpsAgent: new https.Agent({
        rejectUnauthorized: false
      })
    };
    const response = await axios.get(url, config);
    return response.data;
  } catch (error) {
    if (error.response?.status === 403 && retries > 0) {
      console.log(`遇到403,重试剩余次数:${retries - 1}`);
      return fetchQuizletSet(url, retries - 1);
    }
    throw error;
  }
};

4. 检查法律合规性

注意:未经Quizlet允许爬取其内容可能违反服务条款,使用前务必确认相关合规要求,避免法律风险。


内容的提问来源于stack exchange,提问作者Globe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 06:05:14