简介
目标是尽可能自动抓取目标大学、所需院系的在职教师名单和详细信息(主要是联系方式,简历等),结果生成格式化csv文件,包含内容包括姓名、英文名、职称、邮件、电话、部门、个人网站、电话、研究方向等。最大的问题在于各大学校院系的网站千奇百怪,格式不尽相同,工作量大。
思路:爬虫+解析器+存取器
依赖
1
2
3
4
5
6
7
8
9
python 2.7.10
beautifulsoup4==4.4.1
lxml==3.4.4(remove)
requests==2.8.1
Ghost.py-0.2.3
python-imaging
pytesseract
tesseract-ocr(图像识别)
wand(imageMagic的绑定)
其他库
1
2
3
ImageMagic
media-libs/leptonica
app-text/tesseract-3.04.00-r2::gentoo(需要自行下载源码编译training工具)
OCR训练工具
1
jTessBoxEditor
基本使用
我只是写了一个简单的架子,功能:
解析hao123的211/985名单
数据 《=》csv/json相互转化
按照用户选择解析各个学校、学院的在职员工数据(模糊匹配职称、电子邮件、电话等等基本信息),并抓取简历保存在学院目录。
按照设置规则文件抓取目标内容,规则内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 目标所在的区域的tag和attrs(属性)
self.zone_tag = ''
self.zone_attr = {}
# 要抓取的目标标签tag
self.tag_name = tag_name or ''
# 要抓取的目标标签的递归父亲tag列表
# <span><p>
# <a>something</a>
# </p></span>
# 如<a> tag的父亲列表为["p","span"]
self.parents = []
# 1. 目标节点属性
# {
# 'class':true, true或者false表示是否含有此标签
# 'width':'21%',标签为具体值则表示仅当标签=值时抓取
# 'class':['class1','class2'], 标签为列表时表示仅当标签值为列表中的值才成立。暂未用到
# }
self.attrs = {}
# 2. 结果筛选,暂未用到
self.select = []
一般来说,找到合适的zone、目标的tag、属性就能找到要找的内容。
解析员工数据时,先编辑对应学校下面的json文件,在目标学院的json结构里添加抓取规则。然后在学院目录下定义MyHandler.py文件,写合适的解析脚本进行解析即可得到想要的数据。
由于每个学院的解析模式各不相同,所以需要在每个学院目录下自己实现两个方法:
- handler:将找到的目标转化为员工数据实体
- profile_handler:保存简历正文到文件,模糊匹配员工数据并返回
json中的主要数据结构如下所示:
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
"__classname__": "Academy", 表示数据的类型,自动写好的
"__module__": "models", 表示类的模块,自动写好的
"departments": { [*] 找到一个学院的所有教师名单的索引页面,并填写进去,这个页面将用来解析employee(在职员工)
格式为名字:网址
"全职教员":"http://www.math.pku.edu.cn/static/quanzhijiaoyuan.html"
},
departmentsRule结构暂时不用管,没用到
"departmentsRule": {
"__classname__": "ParseRule",
"__module__": "models",
"attrs": {},
"parents": [],
"select": [],
"tag_name": "",
"zone_attr": {},
"zone_tag": ""
},
"departmentsUrl": "", 没用到
"done": false, 没用到
"employees": [], 没用到,自动生成,不用管
"eng_name": "www.math.pku.edu.cn", 自动解析生成学院的英文名字,不用管
"hasDepartments": false, 不用管
"name": "数学科学学院", 自动解析生成,不用管
"parser": null,
"rule": { [*]Rule是你的重点,这是一个规则配置文件
"__classname__": "ParseRule", 表示数据的类型,自动写好的
"__module__": "models", 表示类的模块,自动写好的
"attrs": {}, 目标tag_name的属性,类似zone_attr
"parents": [], [*]这个也是重点,目标的父标签,用于缩小解析范围的
"select": [], 忽略永不到
"tag_name": "a", [*]目标tag,这个也是重点
"zone_attr": {"id":"main"}, [*]目标tag的属性,这个也是重点,如<a class="link">中的class属性为link,所以规则为{"class":"link"}
"zone_tag": "div" [*]目标区域tag,这个也是重点,(标签,如<table>,<html>,<p>都是标签),zone用于缩小网站目标范围,过滤冗余信息
},
"sname": "math", 学院简称
"url": "http://www.math.pku.edu.cn/", 学院主页,自动解析出来的
"web_engine": "urllib2" 一般用urllib2,对于特定的js网站,需要用selen
####菜单
1
2
3
4
5
6
7
8
9
menu0 = '''
q. 退出
p. 打印所有大学名单
1. 抓取211名单到json文件
2. 从json文件导入211名单
3. 构建输出目录
4. 测试抓取院系导航目录
5. 自动猜测并分析出学校的院系导航链接
6. 抓取院系的名称和主页
- out目录下如果存在
china211.json
则将其大学目录数据导入。如果不存在,可运行python run.py
选择菜单1从hao123抓取。 - 编辑
china985.json
,删除不感兴趣的大学。如仅保留985+理工。 - 运行
1
2
3
4
5
$ python run.py
选择6菜单
选择学校
选择院系
开始解析
数据结构
1
2
3
4
5
China211
collges + rule
academies
Department
employees
Parser
Parser主要有两种,一种是SimpleAParser对于简单的链接+简历url正文的教师队伍介绍页面进行解析。一种是SimpleTableParser对表格式的教师队伍介绍页面进行解析。
1
2
3
4
5
6
7
l_parsers = {
"Parser": Parser,
"Hao123_211_Parser": Hao123_211_Parser,
"SimpleAParser": SimpleAParser,
"AutoAcademyParser": AutoAcademyParser,
"SimpleTableParser":SimpleTableParser
}
Models
Models模块包含了相关数据的结构,如College,Academy,Employee类结构,同时提供obj2json和json2obj等串行化/实例化接口。
###浏览器和javascript支持
对于一些比较变态的主页(主要是javascript数据),使用selenium调用firefox获取数据
反爬虫问题
遇到过比较棘手的将邮件等信息用图片方式进行展示的情况,没办法,只能用的OCR方式进行图像文字识别,可能还需要自己训练数据。
其他
- JSon”陷阱”
对于自定义类的json化,需要注意成员必须事先定义好。否则在dump时会出现循环解析
的问题。 - BeautifulSoup解析器
社区推荐优先使用lxml,主要是速度较快。但是使用时发现有时解析不到目标,改为python自带的”html-parser”。后期将分析原因,或者向社区提交bug - 中英文名转换 主要是中文转英文名,使用了pypinyin库
源代码
github地址:https://github.com/yixiaoyang/EduParser/