概述
最近课程作业需要爬取互动百科的词条,花了一周时间先学习了一点scrapy,利用该框架写了一个简单的爬虫
scrapy框架学习:Scrapy入门教程
首先看一下题目的要求:
1.首先实现了一个自动爬取互动百科词条页面的爬虫程序获取百科页面数据。根据互动百科的分类页面来获取对应分类下的所有词条页面。
2.为了构建知识,可以利用百科词条页面结构抽取出了互动百科的中的结构化知识。此外,参考给出的文献中的一种面向中文的开放域实体关系抽取方法,充分利用页面非结构化部分内容包含的知识。
3.为了管理从互动百科页面中抽取出来的知识,要实现一个知识存储系统,该系统接受实体关系三元组作为输入,将之存入以RDF文件格式存储的知识库中。
参考论文:面向互动百科的知识抽取和知识库构建方法研究
这里先实现爬取部分,互动百科的分类页面如下
http://fenlei.baike.com/
那么接下来就是以这些分类下的所有词条作为爬取的对象,其中所有词条对应的URL为:
http://fenlei.baike.com/分类名/list/
例如:
http://fenlei.baike.com/科学家/list/
接下来对应的词条页面里面我们需要爬取的是
1、词条名
2、开放分类
3、简介
4、基本信息
这里先按论文所说存成json格式的数据,比如当前词条为:
{
"infoBox": {
"籍贯:": "台湾",
"性别:": "男",
"经纪公司:": "杰威尔音乐有限公司",
"出生年月:": "1979年1月18日",
"主要成就:": "两届台湾金曲奖最佳国语男歌手获得十五座金曲奖(获奖最多)连续7年获得IFPI香港唱片销量大奖十大销量国语唱片",
"出生地:": "台湾新北",
"毕业院校:": "淡江中学",
"英文名:": "Jay Chou",
"民族:": "汉族",
"血型:": "O",
"职业:": "歌手、音乐人、制作人、导演、商人",
"星座:": "魔羯座",
"国籍:": "中国",
"代表作品:": "龙卷风、简单爱、七里香、夜曲、青花瓷、稻香、头文字D、不能说的秘密、逆战、青蜂侠、天台",
"中文名:": "周杰伦",
"别名:": "周董"
},
"openType:": ["艺人"],
"infoName:": "周杰伦"
}
词条页面的分析:首先词条名我是根据url来获得,因为互动百科词条对应的url为:
http://www.baike.com/wiki/词条名
因此只需要截取到url后面的词条名即可
sel = Selector(response)
#26就是 http://www.baike.com/wiki/ 的长度
pagename = response.url[26:]
'''
去掉不需要的信息,例如:http://www.baike.com/wiki/%E5%91%A8%E6%9D%B0%E4%BC%A6&prd=button_doc_entry
'''
pgnametxt = re.findall(r'.*[&|?]', pagename)
if len(pgnametxt) != 0:
pagename = pgnametxt[0][:-1]
'''
url解码,主要是因为中文的原因,不解码的话就是这样子的%E5%91%A8%E6%9D%B0%E4%BC%
'''
pagename = urllib.unquote(pagename)
pgnameList = []
pgnameList.append(pagename)
接着开放分类以及基本信息框
cla = sel.xpath('//div[@class="place"]/p/a/@title').extract()
sites = sel.xpath('//div[@class="module zoom"]/table/tr/td').extract()
爬虫程序:
# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector
import re
from bs4 import BeautifulSoup
import urllib
class W1Spider(scrapy.Spider):
name = "w1" # 爬虫的名字
allowed_domains = ["www.baike.com", "fenlei.baike.com"] # 允许爬的网站
start_urls = [
"http://fenlei.baike.com" # 起始url
]
def parse(self, response):
namelist = []
sel = Selector(response)
classpage = sel.xpath(
'//div[@class="td w-578"]/dl').extract()
for i in range(len(classpage)):
classname = re.findall(r'>.*?<', classpage[i])
mess = {}
for num in range(len(classname)):
st = classname[num][1:-1]
print (st)
if st == "" or st == " | ":
pass
else:
namelist.append(classname[num][1:-1])
for count in range(len(namelist)):
url = "http://fenlei.baike.com/"+ namelist[count]+"/list"
print (url)
yield scrapy.Request(url, callback=self.parse_onepage)
def parse_onepage(self, response):
soup = BeautifulSoup(response.body, "html.parser")
total = soup.find_all('a', href=re.compile(
r'http://www.baike.com/wiki/.+'))
for href in total:
try:
# print href.attrs['href'][26:]
# 递归爬取,不加callback试过也可以
yield scrapy.Request(href.attrs['href'], callback=self.parse_w1)
except:
continue
def parse_w1(self, response):
soup = BeautifulSoup(response.body, "html.parser")
# 如果不是http://www.baike.com/wiki/说明不是词条,则不作处理不保存信息
total = soup.find_all('a', href=re.compile(
r'http://www.baike.com/wiki/.+'))
if len(total) != 0:
name = {}
infoDict = {}
childinfoDict = ""
sel = Selector(response)
pagename = response.url[26:]
pgnametxt = re.findall(r'.*[&|?]', pagename)
if len(pgnametxt) != 0:
pagename = pgnametxt[0][:-1]
pagename = urllib.unquote(pagename)
pgnameList = []
pgnameList.append(pagename)
sites = sel.xpath(
'//div[@class="module zoom"]/table/tr/td').extract()
cla = sel.xpath('//div[@class="place"]/p/a/@title').extract()
infoDict.setdefault("infoName", ''.join(pgnameList)) # 词条名
infoDict.setdefault("openType", ','.join(cla)) # 开放分类
for site in range(len(sites)):
#link = site.xpath('p/a/@title').extract()
Key = re.findall(r'>.*</strong>', sites[site])
Text = re.findall(r'>.*</span>', sites[site])
# print Key
lastTest = ""
lastKey = ""
test1 = ""
test2 = ""
if len(Key) != 0:
# for num in range(len(Key)):
keytxt = re.findall(r'>.*</a>', Key[0][1:-9])
# print keytxt
if len(keytxt) != 0:
lastKey = keytxt[0][1:-5]
else:
lastKey = Key[0][1:-10]
# print lastKey
if len(Text) != 0:
for num in range(len(Text)):
t1 = re.findall(r'>.*?<', Text[num][:-6])
for i in range(len(t1)):
lastTest = lastTest + t1[i][1:-1]
rtxt = re.compile(r'"')
lastTest = rtxt.sub('', lastTest)
# print lastTest
else: # span 中没有内容
Text = re.findall(r'>.*</a>', sites[site])
# print Text
if len(Text) != 0:
lastTest = Text[0][1:-4]
# print lastTest
t1 = re.findall(r'">.*', lastTest)
# print t1
lastTest = t1[0][2:]
rtxt = re.compile(r'"')
lastTest = rtxt.sub('', lastTest)
# print lastTest
# 先把它存成字典再作为值给键infobox
#childinfoDict.setdefault(lastKey, lastTest)
print (lastKey)
print (lastTest)
if lastKey != "" and lastKey != "":
if len(sites) != 1:
childinfoDict = childinfoDict + lastKey + ":" + lastTest + "@#$#"
else:
childinfoDict = childinfoDict + lastKey + ":" + lastTest
#print (childinfoDict)
infoDict.setdefault("infoBox", childinfoDict) # 信息框的内容
yield infoDict
pipelines.py
import json
import codecs
class MyspiderPipeline(object):
def __init__(self):
self.file = codecs.open('data.json', 'wb', encoding='utf-8')
def process_item(self, item, spider):
line = json.dumps(dict(item)) + ',' + 'n'
self.file.write(line.decode("unicode_escape"))
return item
到此简单的爬虫完成了,第一次写有很多不清楚的但先实现了功能,Python也不是很熟悉,期间遇到很多问题,最烦人的就是互动百科的每个词条里面的格式没有一个统一,比如这个就很坑人了本来以为只有一个空格,后来发现他和自己打的空格不一样彻底醉了。。。
最后
以上就是复杂嚓茶为你收集整理的利用scrapy框架爬取互动百科的词条--存成json的全部内容,希望文章能够帮你解决利用scrapy框架爬取互动百科的词条--存成json所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复