想写一个 GitHub 的拓展小程序,GiHub Trending 必不可少。可 GitHub 未提供 Trending 的 API,只能自己爬了。
作者使用云函数请求网页 HTML 字符串后解析出想要的数据。
噼里啪啦写完了,上线。然后发现云函数访问不了外网,无法使用手机的代理服务,GitHub 在国内也很不稳定,所以经常会请求挂掉。
无意间发现 Vercel 在国内的访问速度不错,又能免费托管云函数,就想到通过 Vercel 代理请求 GitHub Trending,想到就干,弄完效果还不错,不会挂了。
登录/注册 Vercel
新建 Next.js 项目
新建 Next 项目,未接触过 Next 和 Vercel 的同学可以使用 Vercel 提供的 Next.js 模版。Vercel 项目需要仓库托管,可一键克隆模版项目到 GitHub。
编写 API
主要思路是请求网页 HTML 字符串使用 cheerio 解析。
在项目 api/
文件夹下新建 trending.js
(api/
文件夹内文件都会自动转为 Node.js 服务,参考 API Routes),编写请求方法。如何解析我就不赘述了,访问网页打开调试自己找规律就好,直接上代码
import fetch from 'node-fetch';
import cheerio from 'cheerio';
const fetchTrendingList = async () => {
const url = 'https://github.com/trending';
const text = await fetch(url).then((data) => data.text());
const $ = cheerio.load(text);
const list = $('.Box .Box-row')
.get()
.map(repo => {
const $repo = $(repo);
const title = $repo.find('.h3').text().trim();
const [owner, name] = title.split('/').map(v => v.trim());
const description = $(($repo.children())[2]).text().trim();
const language = $repo.find('[itemprop="programmingLanguage"]').text().trim();
const starCount = $repo.find('[aria-label="star"].octicon.octicon-star').parent().text().trim();
return {
owner: {
login: owner,
avatar_url: `https://github.com/${owner}.png`
},
name,
description,
language,
stargazers_count: starCount
};
});
}
export default async (req, res) => {
const resp = await fetchTrendingList();
res.status(200).json(resp);
}
上传到 Git 仓库后触发 Vercel 构建部署,现在访问 https://<vercel-projectname>.vercel.app/trending
即可得到 JSON 返回。
以上不支持筛选参数,接下来增加几行代码是 API 和 GitHub Trending 保持一致。
/**
* 增加参数支持,参数均为可选
*
* @param {object} params
* @param {string} [params.language] Language
* @param {'daily'|'weekly'|'monthly'} [params.since] Date range
* @param {string} [params.spoken_language_code] Spoken Language
*/
const fetchTrendingList = async (params) => {
let url = 'https://github.com/trending';
// 结构出路径参数
const { language, ...query } = params;
if (language) {
url += `/${language}`
}
// 组合 query 字符串
const queryString = Object.keys(query).map((key) => `${key}=${query[key]}`).join('&');
if (queryString) {
url += `?${queryString}`;
}
const text = await fetch(url).then((data) => data.text());
// ... 后面的无需改动
}
export default async (req, res) => {
// 传递 req.query
const resp = await fetchTrendingList(req.query);
res.status(200).json(resp);
}
现在 API 支持了筛选参数,但还没结束。当你访问 https://<vercel-projectname>.vercel.app/api/trending/javascript
时会报 404。因为该路由文件不存在。
一种方案是使用 Next 的动态路由 api/trending/[language].js
,但是这样并不会匹配 api/trending
,官方方案是创建两个路由文件 api/trending/index.js
和 api/trending/[language].js
。要么是相同的代码写两份,要么是写个公用方法引用。
我觉得麻烦,最终采用的 next.config.js 的 Rewrites 配置实现。项目没有 next.config.js 文件的新建。
module.exports = {
async rewrites () {
return [
// :language 必须和 trending.js 里的请求参数 language 一致,language 会包含在 req.query 里
{ source: '/api/trending/:language', destination: '/api/trending' }
];
}
}
到此为止是真的结束了,和 GitHub Trending API 一致。源码就不提供了,都在文章里。
vercel.app
域名未经过 ICP 备案,无法直接添加小程序白名单里。如果你已有备案域名可一在 Vercel 自定义域名然后添加到白名单,使用 wx.request
可以使用手机代理服务。没有备案域名退而求其次使用云函数代理请求 API,不能使用手机代理服务。
GitHub | 扫码体验 |
---|---|
weapp-mark |