admin 发表于 2022-1-16 15:40:00

百科人物爬虫-属性解析

词条分析
百科中的人物属性下还有各行业的人物标签,其对应的描述信息也是不同的,所以在做解析前需要提取出通用的字段。
首先去除《 网络红人、演员、电竞人物、影视幕后人物、音乐人物、明星组合、虚拟人物、体育人物》。

根据剩余人物标签提取特征词:

政治人物:人物履历、职务任免、人物事件、主要贡献、所获荣誉、人物评价
企业人物:人物经历、个人生活、主要贡献、所获荣誉、人物评价
历史人物:人物生平、个人作品、主要成就、轶事典故、史料记载、艺术形象、亲属成员、人物评价
文化任务:人物经历、个人生活、个人作品、主要贡献、获奖记录、人物评价
科学人物:人物经历、个人生活、研究方向、主要成就、所获荣誉、社会任职、人物影响、人物评价
教育人物:人物经历、研究方向、主要成就、获奖记录、社会任职、人物评价
医疗人物:人物经历、研究方向、著作译作、科研成果、获奖情况、学术任职、擅长领域、出诊时间
其他人物:人物经历、主要贡献、所获荣誉、人物评价
其他人物-作家:人物经历、个人生活、出版著作、出版图书、人物评价、所获荣誉
其他人物-科研:人物简介、承担课题、学术成果、奖项荣誉、人物观点、出版作品

经过观察和分析,最终保留以下信息,所以结合人物基本信息栏需要解析的内容有:

中文名、外文名、别名
国籍、民族、籍贯
出生日期、逝世日期
毕业院校、职业、主要成就
性别、职务、学位
人物经历、个人生活、研究方向、成就、获奖|荣誉、任职、影响、评价
页面解析
由于页面数据参差不齐,如何智能解析是百科数据采集的关键。
我构建了一个通用的字段提取器。
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'
}

# 过滤、标签
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'] = 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’))

运行测试:
页: [1]
查看完整版本: 百科人物爬虫-属性解析