parse_resumes.py
3.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/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()