jooooock / wechat-article-exporter

在线批量导出微信公众号文章,支持内嵌的音视频导出,无需搭建任何环境,可100%还原文章样式,支持私有部署
https://wechat-article-exporter.deno.dev
MIT License
595 stars 63 forks source link
download wechat wechat-article

Logo

wechat-article-exporter

Deploy GitHub stars GitHub forks GitHub License GitHub commit activity GitHub last commit

在线批量导出微信公众号文章,支持内嵌的音视频导出,无需搭建任何环境,可100%还原文章样式,支持私有部署。

:dart: 特性

:hammer: 如何使用

  1. 注册一个微信公众号 (已有账号的话跳过)

前往 微信公众平台 注册,服务号和订阅号皆可。

  1. 二维码扫码登录

进入 登录页面,用微信扫描页面上的二维码,然后选择自己的公众号进行登录。

  1. 搜索目标公众号,开始下载文章

通过左上角的公众号切换按钮,搜索自己感兴趣的公众号,如下图所示:

切换账号

:rocket: 私有部署

[!WARNING] 由于项目目前还没有进入稳定状态,所以如果进行了私有部署,请随时关注该项目的最新更新,特别是代理部分的变化,后续将会修改使用策略。

或者你可以修改config/index.ts中的AVAILABLE_PROXY_LIST变量,完全使用自己搭建的节点。

另外,目前只有部署到 Deno Deploy 的文档,如果需要部署到其他平台,请在 Issue 中说明。

部署到 Deno Deploy 1. Fork 该项目 ![create a fork][create-a-fork] 2. 点击 [New Project][new-deno-deploy-project] 在 Deno Deploy 上面创建一个项目,选择你刚fork的仓库,如下图所示: ![create deno deploy project][create-deno-deploy-project] 创建之后如下所示: ![deno deploy project result][deno-deploy-project-create-result] 3. 修改github仓库发布配置 启用仓库的 workflows (默认fork的仓库是禁用的): ![enable github workflows][enable-github-workflows] 修改`.github/workflows/deno_deploy.yml`: ![update workflows project][update-workflows-project] 提交: ![commit changes][commit-changes] 4. 等待发布结果 ![deploy success][deploy-success] ![finally website][finally-website]

:bulb: 原理

在公众号后台写文章时支持搜索其他公众号的文章功能,以此来实现抓取指定公众号所有文章的目的。

:earth_americas: 关于代理池

数据的下载采用代理池的思路,以便解决跨域、防盗链、加速等一系列问题。

目前有以下代理节点:

https://vproxy-01.deno.dev
https://vproxy-02.deno.dev
https://vproxy-03.deno.dev
https://vproxy-04.deno.dev
https://vproxy-05.deno.dev
https://vproxy-06.deno.dev
https://vproxy-07.deno.dev
https://vproxy-08.deno.dev
https://vproxy-09.deno.dev
https://vproxy-10.deno.dev
https://vproxy-11.deno.dev
https://vproxy-12.deno.dev
https://vproxy-13.deno.dev
https://vproxy-14.deno.dev
https://vproxy-15.deno.dev
https://vproxy-16.deno.dev
https://vproxy-01.jooooock.workers.dev
https://vproxy-02.jooooock.workers.dev

以上节点都是部署在 Deno Deploy / Cloudflare Workers 上面的免费账户中,算是白嫖了这些托管平台的流量。

目前这些节点都是公开的,后续打算加入签名验证机制,防止被恶意盗刷。

代理节点代码 (未进行签名验证,请酌情使用):

Deno Deploy ```ts function error(msg: Error | string) { return new Response(msg instanceof Error ? msg.message : msg, { status: 403, }); } async function wfetch(url: string, opt: Record = {}) { if (!opt) { opt = {}; } const options: Record = { method: "GET", headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36", }, }; if (opt.referer) { options.headers["Referer"] = opt.referer; } return await fetch(url, options); } Deno.serve(async (req: Request) => { if (req.method.toLowerCase() !== "get") { return error("Method not allowed"); } const origin = req.headers.get("origin")!; const { searchParams } = new URL(req.url); let url = searchParams.get("url"); if (!url) { return error("url cannot empty"); } url = decodeURIComponent(url); console.log("proxy url:", url); if (!/^https?:\/\//.test(url)) { return error("url not valid"); } const response = await wfetch(url); return new Response(response.body, { headers: { "Access-Control-Allow-Origin": origin, "Content-Type": response.headers.get("Content-Type")!, }, }); }); ```
Cloudflare Worker ```js function error(msg) { return new Response(msg instanceof Error ? msg.message : msg, { status: 403, }); } async function wfetch(url, opt = {}) { if (!opt) { opt = {}; } const options = { method: "GET", headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36", }, }; if (opt.referer) { options.headers["Referer"] = opt.referer; } return await fetch(url, options); } export default { async fetch(req, env, ctx) { if (req.method.toLowerCase() !== "get") { return error("Method not allowed"); } const origin = req.headers.get("origin"); const { searchParams } = new URL(req.url); let url = searchParams.get("url"); if (!url) { return error("url cannot empty"); } url = decodeURIComponent(url); console.log("proxy url:", url); if (!/^https?:\/\//.test(url)) { return error("url not valid"); } const response = await wfetch(url); return new Response(response.body, { headers: { "Access-Control-Allow-Origin": origin, "Content-Type": response.headers.get("Content-Type"), }, }); }, }; ```

关于导出其他格式

本项目暂不支持除html格式之外的其他格式,很大一部分原因是样式很难保真。如果需要其他格式,可以寻找其他格式转换工具。

PDF格式可参考: https://github.com/colin4k/wechat-article-dl

:heart: 感谢

:coffee: 捐赠与支持

如果你觉得本项目帮助到了你,请给作者一个免费的 Star,也可以请作者喝杯咖啡,感谢你的支持!

buy me a coffee 微信赞赏码

:star: Star 历史

Star History Chart

:memo: 许可

MIT