@toc
词条分析
百科中的人物属性下还有各行业的人物标签,其对应的描述信息也是不同的,所以在做解析前需要提取出通用的字段。
首先去除《 网络红人、演员、电竞人物、影视幕后人物、音乐人物、明星组合、虚拟人物、体育人物》。
根据剩余人物标签提取特征词:
政治人物:人物履历、职务任免、人物事件、主要贡献、所获荣誉、人物评价
企业人物:人物经历、个人生活、主要贡献、所获荣誉、人物评价
历史人物:人物生平、个人作品、主要成就、轶事典故、史料记载、艺术形象、亲属成员、人物评价
文化任务:人物经历、个人生活、个人作品、主要贡献、获奖记录、人物评价
科学人物:人物经历、个人生活、研究方向、主要成就、所获荣誉、社会任职、人物影响、人物评价
教育人物:人物经历、研究方向、主要成就、获奖记录、社会任职、人物评价
医疗人物:人物经历、研究方向、著作译作、科研成果、获奖情况、学术任职、擅长领域、出诊时间
其他人物:人物经历、主要贡献、所获荣誉、人物评价
其他人物-作家:人物经历、个人生活、出版著作、出版图书、人物评价、所获荣誉
其他人物-科研:人物简介、承担课题、学术成果、奖项荣誉、人物观点、出版作品
经过观察和分析,最终保留以下信息,所以结合人物基本信息栏需要解析的内容有:
- 中文名、外文名、别名
- 国籍、民族、籍贯
- 出生日期、逝世日期
- 毕业院校、职业、主要成就
- 性别、职务、学位
- 人物经历、个人生活、研究方向、成就、获奖|荣誉、任职、影响、评价
页面解析
由于页面数据参差不齐,如何智能解析是百科数据采集的关键。
我构建了一个通用的字段提取器。
import requests,re
from lxml import etree
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36'
}
# 过滤[n]、[n-n]标签
def filter_label(para):
for label_num in re.findall('\[\d+\]|\[\d+-\d+\]', para):
para = para.replace(label_num, '')
return para
def get_item(url):
doc = requests.get(url,headers=headers).text
e = etree.HTML(doc)
item = {}
item['baike_url'] = url
# 封面图
item['baike_pic'] = ''.join(e.xpath('//div[@class="summary-pic"]/a/img/@src'))
#print("封面图片:",item['pic'])
# 个人简介
item['baike_desc'] = ''
for desc in e.xpath('//div[@class="lemma-summary"]/div[@class="para"]'):
para = ''.join(desc.xpath('.//text()')).replace('\n','')
para = filter_label(para)
item['baike_desc']+=para+'\n'
#print("人物简介:",item['baike_desc'])
# 基本信息
item['baike_basicInfo'] = {}
dt = e.xpath('//div[@class="basic-info J-basic-info cmn-clearfix"]/dl/dt')
dd = e.xpath('//div[@class="basic-info J-basic-info cmn-clearfix"]/dl/dd')
for t,d in zip(dt,dd):
key = ''.join(''.join(t.xpath('./text()')).split())
value = ''.join(''.join(d.xpath('.//text()')).split())
item['baike_basicInfo'][key] = value
#print("基本信息:",item['baike_basicInfo'])
# 通用提取器
def parse_label(label):
re_rule = f'<a name=".*?{label}" class="lemma-anchor " ></a>\n</div>(.*?)<div class="anchor-list ">'
experiences = re.findall(re_rule, doc, re.S)
labels = []
if experiences:
exper = ''.join(experiences)
ex = etree.HTML(exper)
labels = filter_label(''.join(ex.xpath('//div[@class="para"]//text()')))
return labels
# 经历
exper = parse_label('经历')
if exper:
exper = exper.split(';')
# 方向
field = parse_label('方向')
if not field:
field = parse_label('领域')
# 兼职
social = parse_label('兼职')
if social:
social = social.split(';')
# 荣誉
awards = parse_label('荣誉')
if not awards:
awards = parse_label('获奖')
item['baike_experience'] = exper
item['baike_awards'] = awards
item['baike_social'] = social
item['baike_field'] = field
item['baike_results'] = parse_label('成果')
item['baike_life'] = parse_label('生活')
item['baike_affect'] = parse_label('影响')
item['baike_eval'] = parse_label('评价')
return item
运行测试
如果说你采集的人物有其他比较明显的字段,比如课题、科普、作品等。
可以通过parse_labe增加字段,进行智能解析。
print(get_item('https://baike.baidu.com/item/%E7%8E%8B%E5%85%83%E5%8D%93'))
运行测试: