创建一个新网站,一开始没有内容,通常需要抓取其他人的网页内容,一般的操作步骤如下:
根据url下载网页内容,针对每个网页的html结构特征,利用正则表达式,或者其他的方式,做文本解析,提取出想要的正文。
为每个网页写特征分析这个还是太耗费开发的时间,我的思路是这样的。
Python的BeautifulSoup包大家都知道吧,
import BeautifulSoup soup = BeautifulSoup.BeautifulSoup(html)
利用这个包先把html里script,style给清理了:
[script.extract() for script in soup.findAll(‘script‘)] [style.extract() for style in soup.findAll(‘style‘)]
清理完成后,这个包有一个prettify()函数,把代码格式给搞的标准一些:
soup.prettify()
然后用正则表达式,把所有的HTML标签全部清理了:
reg1 = re.compile("<[^>]*>") content = reg1.sub(‘‘,soup.prettify())
剩下的都是纯文本的文件了,通常是一行行的,把空白行给排除了,这样就会知道总计有多少行,每行的字符数有多少,我用excel搞了一些每行字符数的统计,如下图:
x坐标为行数,y坐标为该行的字符数
很明显,会有一个峰值,81~91行就应该是这个网页的正文部分。我只需要提取81~91行的文字就行了。
问题来了,照着这个思路,有什么好的算法能够通过数据分析的方式统计出长文本的峰值在哪几行?
BeautifulSoup不仅仅只是可以查找,定位和修改文档内容,同样也可以用一个好的 格式进行输出显示。BeautifulSoup可以处理不同类型的输出:
- 格式化的输出
- 非格式化的输出
格式化输出
BeautifulSoup中有内置的方法prettfy()来实现格式化输出。比如:
- from bs4 import BeautifulSoup
- html_markup = “””<p class=”ecopyramid”>
- <ul id=”producers”>
- <li class=”producerlist”>
- <div class=”name”>plants</div>
- <div class=”number”>100000</div>
- </li>
- <li class=”producerlist”>
- <div class=”name”>algae</div>
- Output in Beautiful Soup
- <div class=”number”>100000</div>
- </li>
- </ul>”””
- soup = BeautifulSoup(html_markup,“lxml”)
- print(soup.prettify())
输出:
prettify()可以用于BeautifulSoup对象也可以用于任何标签对象。比如:
- producer_entry = soup.ul
- print(producer_entry.prettify())
非格式化输出
可以使用str()和unicode()来进行非格式化输出。
如果我们对BeautifulSoup对象和标签对象使用str()方法,那么得到的就是一般的字符串输出样式。
我们也可以使用前篇讲到的encode()方法来指定编码格式的输出。
对BeautifulSoup对象或标签对象使用decode()方法来得到Unicode字符串。
BeautifulSoup中的输出格式化
HTML实体编码可以放进HTML文档中用来表示特别的字符和标识。这些标识不存在于键盘上,这些HTML实体编码只是当浏览器打开后才回看到效果。
在输出方法中,只有这几个HTML编码有点例外。>和<和&三个符号。除此之外其他的特别标识都是被转换成Unicode编码当创建BeautifulSoup对象时,且当使用Prettify()方法或者其他方法输出时,我们只能得到UTF-8格式的字符串。
html_markup = “””<html>
<body>& & ampersand
¢ ¢ cent
? © copyright
÷ ÷ divide
> > greater than
</body>
</html>
输出:
可以看到两个没有被转换。BeautifulSoup自带的输出格式器来控制输出。输出格式器有以下几种类型。
- miimal
- html
- None
- function
我们可以在输出方法中传递上述输出格式器参数,如prettify(),ncode(),decode()
miimal格式化
在这种格式化模式下,字符串被处理成一个有效的HTML代码。这是默认的格式化输出,此时输出结果就和前面的一样。不能转换&, >和<
Html格式化
这种格式化模式下,BeautifulSoup将会将Unicode字符转换成HTML编码形式。
print(soup.prettify(formatter=”html”))
输出:
None格式化
这种情况下,BeautifulSoup不会改变字符串。这会导致产生一个非法的HTML代码。
- print(soup.prettify(formatter=None))
输出:
函数格式化
我们可以定义一个函数来处理字符串。比如去掉a字符。
- def remove_chara(markup):
- return markup.replace(“a”,””)
- soup = BeautifulSoup(html_markup,“lxml”)
- print(soup.prettify(formatter=remove_chara))
输出:
注意,其中字符a被替换掉了,但是注意的是&, >,和<也被转换了。
使用get_text()
从网页中得到文本是常见的工作,BeautifulSoup提供了get_text()方法来达到目的。
如果我们只想得到BeautifulSoup对象的文本或标签对象的文本内容,我们可以使用get_text()方法。比如:
- html_markup = “””<p class=”ecopyramid”>
- <ul id=”producers”>
- <li class=”producerlist”>
- <div class=”name”>plants</div>
- <div class=”number”>100000</div>
- </li>
- <li class=”producerlist”>
- <div class=”name”>algae</div>
- <div class=”number”>100000</div>
- </li>
- </ul>”””
- soup = BeautifulSoup(html_markup,“lxml”)
- print(soup.get_text())
输出:
plants
100000
algae
100000
get_text()方法返回BeautifulSoup对象或标签对象中的文本内容,其为一个Unicode字符串。但是get_text()有个问题是它同样也会返回javascript代码。
去掉javascript代码的方法如下:
- [x.extract() for x in soup_packtpage.find_all(‘script’)]
这样就会用处掉所有脚本元素。