parse_resumes.py 3.01 KB
#!/usr/bin/env python3
"""读取 hpbr_bosszhipin_client.db,把 Contact 表(联系人摘要) + MessageTable 里的
resume(招聘模式收到的候选人简历,ChatResumeBean) / job(牛人模式收到的职位卡片,
ChatJobBean) 都反序列化导出成 JSON。两者都是明文 Java Object Serialization,
不需要解密。myRole=1 表示这条联系人是"你当老板、对方是候选人",myRole=0 表示
"你当牛人、对方是招聘方"——同一套 Contact 表字段两种角色复用,见 README 第五节。

用法: python3 parse_resumes.py [data/hpbr_bosszhipin_client.db] > resumes.json
"""
import json
import sqlite3
import sys
from pathlib import Path

import javaobj

DB_PATH = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).parent / "data/hpbr_bosszhipin_client.db"


def to_plain(value):
    """把 javaobj 解出来的对象树递归拍平成 JSON 能序列化的 dict/list/基础类型。"""
    if isinstance(value, (str, int, float, bool)) or value is None:
        return value
    if isinstance(value, (list, tuple)):
        return [to_plain(v) for v in value]
    if isinstance(value, dict):
        return {k: to_plain(v) for k, v in value.items()}
    if hasattr(value, "__dict__"):
        return {
            k: to_plain(v)
            for k, v in vars(value).items()
            if k not in ("classdesc", "annotations")
        }
    return str(value)


def parse_blob(blob: bytes):
    obj = javaobj.loads(blob)
    return to_plain(obj)


def collect(con, column, out_key):
    """从 MessageTable 里挑出某个 BLOB 列(resume 或 job)非空的行,反序列化。"""
    rows = []
    for row in con.execute(
        f"SELECT mid, fromUid, toUid, time, {column} FROM MessageTable WHERE {column} IS NOT NULL"
    ):
        try:
            parsed = parse_blob(row[column])
        except Exception as e:
            parsed = {"_parse_error": str(e)}
        rows.append(
            {
                "mid": row["mid"],
                "fromUid": row["fromUid"],
                "toUid": row["toUid"],
                "time": row["time"],
                out_key: parsed,
            }
        )
    return rows


def main():
    con = sqlite3.connect(str(DB_PATH))
    con.row_factory = sqlite3.Row

    contacts = {
        row["friendId"]: dict(row)
        for row in con.execute(
            "SELECT friendId, friendName, myRole, expectPositionName, expectSalary, degree, "
            "workYear, workplace, gender, age, currentInterviewDesc, exchangeResumeUrl, "
            "videoResumeUrl, bossCompanyName, bossJobPosition, positionName, salaryDesc, jobId, "
            "note, lastChatText, lastChatTime FROM Contact"
        )
    }

    resumes = collect(con, "resume", "resume")  # myRole=1: 你当老板收到的候选人简历
    jobs = collect(con, "job", "job")  # myRole=0: 你当牛人收到的职位卡片

    result = {"contacts": list(contacts.values()), "resumes": resumes, "jobs": jobs}
    json.dump(result, sys.stdout, ensure_ascii=False, indent=2)


if __name__ == "__main__":
    main()