字节笔记本

2026年2月23日

website-hot-hub 微信读书爬虫模块解析

本文介绍 website-hot-hub 项目中的微信读书爬虫模块 website_weread.py,该模块实现了自动抓取微信读书平台热门书籍榜单数据的功能,支持数据归档和 README 自动更新。

项目简介

website-hot-hub 是一个开源的多平台热点数据抓取项目,支持 36Kr、bilibili、GitHub、抖音、掘金、微信读书、快手等主流平台。项目采用 Python 开发,通过 GitHub Actions 实现每小时自动抓取数据并按天归档。

website_weread.py 是该项目中专门用于抓取微信读书热门榜单的模块,实现了从微信读书 Web 端获取飙升榜数据的功能。

核心特性

  • 自动数据抓取:定时抓取微信读书飙升榜数据
  • 数据清洗处理:将原始 API 数据转换为结构化格式
  • 增量更新机制:支持合并历史数据,避免重复记录
  • 多格式输出:支持 JSON 原始数据、Markdown 归档、README 更新
  • 自动归档:按日期自动归档数据到指定目录

技术栈

  • Python 3.x - 主要开发语言
  • requests - HTTP 请求库
  • urllib3 - 连接池和重试机制
  • pathlib - 文件路径处理
  • contextlib - 上下文管理器

核心代码解析

1. 请求会话管理

使用上下文管理器实现带重试机制的 HTTP 会话:

python
@contextlib.contextmanager
def request_session():
    s = requests.session()
    try:
        s.headers.update(headers)
        s.mount("http://", HTTPAdapter(max_retries=retries))
        s.mount("https://", HTTPAdapter(max_retries=retries))
        yield s
    finally:
        s.close()

2. 数据获取与清洗

python
@staticmethod
def get_raw() -> dict:
    """从微信读书 API 获取原始数据"""
    ret = {}
    try:
        with request_session() as s:
            resp = s.get(url, timeout=30)
            ret = resp.json()
    except:
        logger.exception("get data failed")
        raise
    return ret

@staticmethod
def clean_raw(raw_data: dict) -> typing.List[typing.Dict[str, typing.Any]]:
    """清洗原始数据,提取书籍标题和链接"""
    ret: typing.List[typing.Dict[str, typing.Any]] = []
    for item in raw_data.get("books", []):
        ret.append({
            "title": item["bookInfo"]["title"],
            "url": f"https://weread.qq.com/web/bookDetail/{get_weread_id(item['bookInfo']['bookId'])}",
        })
    return ret

3. 数据合并与去重

python
@staticmethod
def merge_data(
    cur: typing.List[typing.Dict[str, typing.Any]],
    another: typing.List[typing.Dict[str, typing.Any]],
):
    """合并两组数据,以 URL 为键去重"""
    merged_dict: typing.Dict[str, typing.Any] = {}
    for item in chain(cur, another):
        merged_dict[item["url"]] = item["title"]
    return [{"url": k, "title": v} for k, v in merged_dict.items()]

4. Markdown 列表生成

python
@staticmethod
def create_list(content: typing.List[typing.Dict[str, typing.Any]]) -> str:
    """生成 Markdown 格式的书籍列表"""
    topics = []
    template = """<!-- BEGIN WEREAD -->
<!-- 最后更新时间 {update_time} -->
{topics}
<!-- END WEREAD -->"""
    for item in content:
        topics.append(f"1. [{item['title']}]({item['url']})")
    template = template.replace("{update_time}", current_time())
    template = template.replace("{topics}", "\n".join(topics))
    return template

5. README 自动更新

python
def update_readme(self, content: typing.List[typing.Dict[str, typing.Any]]) -> str:
    """更新 README.md 中的微信读书板块"""
    with open("./README.md", "r") as fd:
        readme = fd.read()
    return re.sub(
        r"<!-- BEGIN WEREAD -->[\W\w]*<!-- END WEREAD -->",
        self.create_list(content),
        readme,
    )

使用示例

独立运行

python
from website_weread import WebSiteWeRead

# 创建实例并运行
weread_obj = WebSiteWeRead()
weread_obj.run(update_readme=True)

作为模块调用

python
from website_weread import WebSiteWeRead

weread_obj = WebSiteWeRead()
result = weread_obj.run(update_readme=False)

# 返回数据结构
{
    "section_name": "WEREAD",
    "content": "<!-- BEGIN WEREAD -->...",
    "data_count": 10
}

数据存储结构

text
project-root/
├── raw/weread/           # 原始 JSON 数据
│   └── 2026-02-23.json
├── archives/weread/      # Markdown 归档
│   └── 2026-02-23.md
└── README.md             # 自动更新的主文档

API 参考

WebSiteWeRead 类

方法说明返回值
get_raw()获取微信读书 API 原始数据dict
clean_raw(raw_data)清洗原始数据List[Dict]
merge_data(cur, another)合并并去重数据List[Dict]
create_list(content)生成 Markdown 列表str
update_readme(content)更新 README 文件str
create_archive(content, date)创建归档内容str
run(update_readme=True)执行完整流程bool / dict

注意事项

  1. API 限制:微信读书 Web API 可能有访问频率限制,建议合理设置抓取间隔
  2. 数据格式:API 返回格式可能随平台更新而变化,需要定期维护
  3. 编码处理:中文内容使用 ensure_ascii=False 确保正确存储
  4. 错误处理:网络异常时会记录日志并抛出异常

项目链接

分享: