Beautiful Soup
在使用正则化匹配时无法去除标签,所以使用BeautifulSoup,BeautifulSoup可以很好的第三方用于解析网站,查找信息的包
Beautiful soup basic
安装Beautifulsoup
命令行或Anaconda Promote cd到../Lib/site-package
pip install beautifulSoup4
基本使用方法
找到标签
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, features='lxml')
print(soup.h1) #打印<h1>标签内容
查找链接
all_href = soup.find_all('a')
all_href = [l['href'] for l in all_href]
print('\n', all_href)
根据CSS查找
CSS定义了class,可以根据class来查找想要的信息,对于以下html代码
<head>
...
<style>
.jan {
background-color: yellow;
}
...
.month {
color: red;
}
</style>
</head>
<body>
...
<ul>
<li class="month">一月</li>
<ul class="jan">
<li>一月一号</li>
<li>一月二号</li>
<li>一月三号</li>
</ul>
...
</ul>
</body>
在python中查找
soup = BeautifulSoup(html, features='lxml')
# use class to narrow search
month = soup.find_all('li', {"class": "month"})
for m in month:
print(m.get_text())
"""
一月
二月
三月
四月
五月
"""
jan = soup.find('ul', {"class": 'jan'})
d_jan = jan.find_all('li') # use jan as a parent
for d in d_jan:
print(d.get_text())
"""
一月一号
一月二号
一月三号
"""
BeautifulSoup使用正则表达式
利用正则表达选取图片
在网页中的图片都在这样一个tag中
<td>
<img src="https://.../.jpg">
</td>
所以, 我们可以用 soup 将这些 tag 全部找出来, 但是每一个 img 的链接(src)都可能不同. 或者每一个图片有的可能是 jpg 有的是 png, 如果我们只想挑选 jpg 形式的图片, 我们就可以用这样一个正则 r’.*?.jpg’ 来选取. 把正则的 compile 形式放到 BeautifulSoup 的功能中, 就能选到符合要求的图片链接了.
soup = BeautifulSoup(html, features='lxml')
img_links = soup.find_all("img", {"src": re.compile('.*?\.jpg')})
for link in img_links:
print(link['src'])
同样的,查找链接
links = soup.find_all('a', {'href': re.compile('https://morvan.*')})
for link in course_links:
print(link['href'])
网络爬虫
爬虫会在网络中按照一定规律移动
在百度百科的爬虫词条,<a href=https://baike.baidu.com/item/网络爬虫/5162711target='_blank' >
页面中所有的链接都以item开头,但不是所有词条,所有需要进一步筛选
<a target="_blank" href="/item/%E8%9C%98%E8%9B%9B/8135707" data-lemmaid="8135707">蜘蛛</a>
<a target="_blank" href="/item/%E8%A0%95%E8%99%AB">蠕虫</a>
<a target="_blank" href="/item/%E9%80%9A%E7%94%A8%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E">通用搜索引擎</a>
制作爬虫
导入一些模块, 设置起始页. 并将 /item/… 的网页都放在 his 中, 做一个备案, 记录我们浏览过的网页.
from bs4 import BeautifulSoup
from urllib.request import urlopen
import re
import random
base_url = "https://baike.baidu.com"
his = ["/item/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/5162711"]
接着我们先不用循环, 对一个网页进行处理, 走一遍流程, 然后加上循环, 让我们的爬虫能在很多网页中爬取. 下面做的事情, 是为了在屏幕上打印出来我们现在正在哪张网页上, 网页的名字叫什么.
url = base_url + his[-1]
html = urlopen(url).read().decode('utf-8')
soup = BeautifulSoup(html, features='lxml')
print(soup.find('h1').get_text(), ' url: ', his[-1])
# 网络爬虫 url: /item/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/5162711
接下来我们开始在这个网页上找所有符合要求的 /item/ 网址. 使用一个正则表达式(正则教程) 过滤掉不想要的网址形式. 这样我们找到的网址都是 /item/%xx%xx%xx...
这样的格式了. 之后我们在这些过滤后的网页中随机选一个, 当做下一个要爬的网页. 不过有时候很不幸, 在 sub_urls 中并不能找到合适的网页, 我们就往回跳一个网页, 回到之前的网页中再随机抽一个网页做同样的事.
# find valid urls
sub_urls = soup.find_all("a", {"target": "_blank", "href": re.compile("/item/(%.{2})+$")})
if len(sub_urls) != 0:
his.append(random.sample(sub_urls, 1)[0]['href'])
else:
# no valid sub link found
his.pop()
print(his)
# ['/item/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/5162711', '/item/%E4%B8%8B%E8%BD%BD%E8%80%85']
有了这套体系, 我们就能把它放在一个 for loop 中, 让它在各种不同的网页中跳来跳去.
his = ["/item/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/5162711"]
for i in range(20):
url = base_url + his[-1]
html = urlopen(url).read().decode('utf-8')
soup = BeautifulSoup(html, features='lxml')
print(i, soup.find('h1').get_text(), ' url: ', his[-1])
# find valid urls
sub_urls = soup.find_all("a", {"target": "_blank", "href": re.compile("/item/(%.{2})+$")})
if len(sub_urls) != 0:
his.append(random.sample(sub_urls, 1)[0]['href'])
else:
# no valid sub link found
his.pop()
这样我们就能观看我们的爬虫现在爬去了哪? 是不是爬到了和 网页爬虫 起始页完全不相关的地方去了.
0 网络爬虫 url: /item/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/5162711
1 路由器 url: /item/%E8%B7%AF%E7%94%B1%E5%99%A8
2 服务等级 url: /item/%E6%9C%8D%E5%8A%A1%E7%AD%89%E7%BA%A7
...
17 呼损率 url: /item/%E5%91%BC%E6%8D%9F%E7%8E%87
18 服务等级 url: /item/%E6%9C%8D%E5%8A%A1%E7%AD%89%E7%BA%A7
19 呼损率 url: /item/%E5%91%BC%E6%8D%9F%E7%8E%87