腾讯DeepOcean:从互联网上爬取的语料经验分享
优采云 发布时间: 2021-06-17 02:08
腾讯DeepOcean:从互联网上爬取的语料经验分享
用python3教你任何Html主要内容提取功能
更新时间:2018-11-05 14:14:41 作者:腾讯深海
这个文章主要介绍python3的使用,教大家任意Html主要内容提取功能,主要使用requests、lxml、json等模块。文章一一介绍了这些模块。有需要的朋友可以参考
本文将与大家分享一些从互联网上抓取语料的经验。
0x1 工具准备
工欲善其事,必先利其器。爬取语料库的基础是基于python的。
我们基于python3开发,主要使用以下模块:requests, lxml, json。
各模块功能简介
01|请求
requests 是 Python 第三方库,特别方便处理 URL 资源。它的官方文档上写着一个大大的标语:HTTP for Humans(为人类使用HTTP而生)。对比使用python自带的urllib的体验,笔者认为使用requests的体验比urllib高一个数量级。
让我们简单比较一下:
网址:
import urllib2
import urllib
URL_GET = "https://api.douban.com/v2/event/list"
#构建请求参数
params = urllib.urlencode({'loc':'108288','day_type':'weekend','type':'exhibition'})
#发送请求
response = urllib2.urlopen('?'.join([URL_GET,'%s'])%params)
#Response Headers
print(response.info())
#Response Code
print(response.getcode())
#Response Body
print(response.read())
请求:
import requests
URL_GET = "https://api.douban.com/v2/event/list"
#构建请求参数
params = {'loc':'108288','day_type':'weekend','type':'exhibition'}
#发送请求
response = requests.get(URL_GET,params=params)
#Response Headers
print(response.headers)
#Response Code
print(response.status_code)
#Response Body
print(response.text)
我们可以发现这两个库还是有一些区别的:
1. 参数构造:urllib需要对参数进行urlencode,比较麻烦;请求不需要额外的编码,非常简洁。
2. 请求发送:urllib需要构造额外的url参数,成为符合要求的表单; requests 简洁很多,直接获取对应的链接和参数。
3. 连接方法:看返回数据的头信息的“连接”。使用urllib库时,"connection":"close"表示每次请求结束时关闭socket通道,请求库使用urllib3,多次请求复用一个socket,"connection":"keep-alive ",表示多个请求使用一个连接,消耗资源少
4.编码方式:requests库的Accept-Encoding编码方式比较完善,这里就不举例了。
综上所述,使用requests更加简洁易懂,极大的方便了我们的开发。
02|lxml
BeautifulSoup 是一个库,而 XPath 是一种技术。 python中最常用的XPath库是lxml。
当我们得到请求返回的页面时,如何得到我们想要的数据?此时,lxml 是一个强大的 HTML/XML 解析工具。 Python从不缺少解析库,那么为什么要在众多库中选择lxml呢?我们选择另一个知名的HTML解析库BeautifulSoup进行对比。
让我们简单比较一下:
美汤:
from bs4 import BeautifulSoup #导入库
# 假设html是需要被解析的html
#将html传入BeautifulSoup 的构造方法,得到一个文档的对象
soup = BeautifulSoup(html,'html.parser',from_encoding='utf-8')
#查找所有的h4标签
links = soup.find_all("h4")
lxml:
from lxml import etree
# 假设html是需要被解析的html
#将html传入etree 的构造方法,得到一个文档的对象
root = etree.HTML(html)
#查找所有的h4标签
links = root.xpath("//h4")
我们可以发现这两个库还是有一些区别的:
1.解析html:BeautifulSoup的解析方法和JQ类似。 API 非常人性化,支持 css 选择器; lxml的语法有一定的学习成本
2.性能:BeautifulSoup是基于DOM的,会加载整个文档,解析整个DOM树,所以时间和内存开销会大很多;而lxml只会部分遍历,lxml是c写的,BeautifulSoup是python写的,明显的表现就是lxml>>BeautifulSoup。
综上所述,使用BeautifulSoup更加简洁易用。 lxml虽然有一定的学习成本,但也非常简单易懂。最重要的是它是用 C 编写的,而且速度要快得多。这是给作者的。有症状,自然选择lxml。
03|json
Python 自带 json 库。对于基本的json处理,自己的库就完全够用了。但是如果你想更懒,可以使用第三方json库,常见的有demjson和simplejson。
这两个库,无论是导入模块的速度,还是编解码的速度,simplejson都比较好,simplejson的兼容性也比较好。所以如果要使用square库,可以使用simplejson。
0x2 确定语料来源
准备好武器后,下一步就是确定爬升的方向。
以电竞语料库为例,现在我们要爬取电竞相关语料库。熟悉的电竞平台有企鹅电竞、企鹅电竞和企鹅电竞(眯眼),所以我们以企鹅电竞的直播游戏为数据源进行爬取。
我们登录企鹅电竞官网,进入游戏列表页面。我们可以发现页面上有很多游戏。手动编写这些游戏名称的收益显然不高,于是我们开始了我们爬虫的第一步:游戏列表爬取。
import requests
from lxml import etree
# 更新游戏列表
def _updateGameList():
# 发送HTTP请求时的HEAD信息,用于伪装为浏览器
heads = {
'Connection': 'Keep-Alive',
'Accept': 'text/html, application/xhtml+xml, */*',
'Accept-Language': 'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3',
'Accept-Encoding': 'gzip, deflate',
'User-Agent': 'Mozilla/6.1 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
}
# 需要爬取的游戏列表页
url = 'https://egame.qq.com/gamelist'
# 不压缩html,最大链接时间为10妙
res = requests.get(url, headers=heads, verify=False, timeout=10)
# 为防止出错,编码utf-8
res.encoding = 'utf-8'
# 将html构建为Xpath模式
root = etree.HTML(res.content)
# 使用Xpath语法,获取游戏名
gameList = root.xpath("//ul[@class='livelist-mod']//li//p//text()")
# 输出爬到的游戏名
print(gameList)
我们拿到这几十款游戏后,下一步就是爬取这几十款游戏。这时候问题来了,这几十款游戏我们要从哪个网站爬取呢tappap呢?多玩? 17173?对这些网站进行分析后发现,这些网站只有一些热门游戏文章语料,一些冷门或不受欢迎的游戏,比如《灵魂讨价还价》、《奇迹:觉醒》、《死神》来”等,很难在这些网站上找到大量文章语料库,如图:
我们可以发现《奇迹:觉醒》和《灵魂讨价还价》的文章语料库非常少,数量不符合我们的要求。那么有没有更通用的资源站点,拥有极其丰富的文章语料库,可以满足我们的需求。
其实,冷静下来考虑一下。我们每天都在使用这个资源网站,那就是百度。我们在百度新闻中搜索相关游戏,得到了一个搜索结果列表。几乎所有链接到这些列表的网页都与搜索结果密切相关。这样就可以轻松解决数据源不足的问题。但是这时候出现了一个新问题,又是一个比较难解决的问题——如何抓取任意网页的文章内容?
因为不同的网站有不同的页面结构,我们无法预测哪些网站数据会被爬取,而且我们不可能为每个网站写一个爬虫,所以工作量是难以想象的!但是我们不能简单粗暴地抓取页面上的所有文字,使用这样的语料进行训练无疑是一场噩梦!
和各种网站斗智勇斗智斗勇,打听资料,思考,终于找到了一个比较大的方案。给大家说说作者的想法。
0x3 任何网站的文章语料爬行
01|提取方法
1)基于Dom树提取文本
2)基于页面分割查找正文块
3)基于标记窗口的文本提取
4)基于数据挖掘或机器学习
5)基于行块分布函数的文本提取
02|提取原理
大家看到这些类型都有点懵,究竟是怎么提取出来的?让作者慢慢说。
1)基于Dom树的文本提取:
这种方法主要是通过更规范的HTML构建一个Dom树,然后基柜遍历Dom,对比识别各种非文本信息,包括广告、链接和非重要节点信息,提取非-text information ,剩下的自然就是短信了。
但是这个方法有两个问题
① 它特别依赖于 HTML 的良好结构。如果我们抓取的网页不是按照 W3c 规范编写的,这种方法不是很合适。
②树的建立和遍历的时间复杂度和空间复杂度都很高,而且由于HTML标签不同,树的遍历方法也不同。
2)根据分页查找文本块:
此方法使用 HTML 标签中的分割线和一些视觉信息(如文本颜色、字体大小、文本信息等)。
这个方法有问题:
① 不同的网站HTML 风格差异很大,没有办法统一划分,也不能保证通用性。
3)基于标记窗口的文本提取:
首先科普的概念——标签窗口,我们把两个标签和里面收录的文字组合成一个标签窗口(比如h1中的“我是h1”就是标签窗口的内容),取出标签窗口的文本。
该方法首先取文章标题和HTML中的所有标记窗口,然后对它们进行分词。然后计算标题的序列和标签窗口的文本序列之间的词距L。如果 L 小于阈值,则将标签窗口中的文本视为主要文本。
这个方法虽然看起来不错,但实际上是有问题的:
① 需要对页面上的所有文字进行分段,效率不高。
②词距阈值难以确定,不同的文章阈值不同。
4)基于数据挖掘或机器学习
使用大数据进行训练,让机器提取正文。
这个方法绝对是优秀的,但是需要训练前的html和text数据。我们不会在这里讨论。
5)基于行块分布函数的文本提取
对于任何网页,其正文和标签总是混合在一起。这种方法的核心有一个亮点:①身体面积的密度; ②线块的长度;一个网页的body区域一定是文本信息分布最密集的区域之一,这个区域可能是最大的(长评论信息和短文本)。因此,同时判断块长。
实施思路:
①我们先把标签中的HTML去掉,只留下所有的文字,去掉标签后留下所有空白的位置信息,我们称之为Ctext;
②为每个Ctext取周围k行(k
③从Cblock中去除所有空白字符,文本总长度称为Clen;
④ 以Ctext为横坐标,每行的Clen为纵坐标,建立坐标系。
以这个网页为例:网页的文本区域从第145行到第182行。
从上图可以看出,正确的文本区域都是分布函数图上值最高的连续区域。该区域通常收录一个膨胀点和一个凹陷点。因此,将网页正文的提取问题转化为线块分布函数上的膨胀点和下垂点两个边界点。这两个边界点所收录的区域收录当前网页的最大行块长度并且是连续的。 .
经过大量实验证明,该方法对中文网页文本的提取具有较高的准确率。这种算法的优点是行块功能不依赖于HTML代码,与HTML标签无关。实现简单,准确率高。 .
主要逻辑代码如下:
# 假设content为已经拿到的html
# Ctext取周围k行(k max_text_len and (not boolstart)):
# Cblock下面3个都不为0,认为是正文
if (Ctext_len[i + 1] != 0 or Ctext_len[i + 2] != 0 or Ctext_len[i + 3] != 0):
boolstart = True
start = i
continue
if (boolstart):
# Cblock下面3个中有0,则结束
if (Ctext_len[i] == 0 or Ctext_len[i + 1] == 0):
end = i
boolend = True
tmp = []
# 判断下面还有没有正文
if(boolend):
for ii in range(start, end + 1):
if(len(lines[ii]) < 5):
continue
tmp.append(lines[ii] + "n")
str = "".join(list(tmp))
# 去掉版权信息
if ("Copyright" in str or "版权所有" in str):
continue
main_text.append(str)
boolstart = boolend = False
# 返回主内容
result = "".join(list(main_text))
0x4 结论
此时,我们可以获取任何内容的文章语料库,但这只是开始。得到这些语料后,我们需要进行清洗、分词、词性标注等,才能得到一个真正可用的语料。
总结
以上就是小编给大家介绍的使用python3教大家任何Html主要内容提取功能,希望对大家有所帮助,有问题请给我留言,小编会回复的及时给你。非常感谢您对Script Home网站的支持!