网络爬虫,首先得获取到网络资源。关于使用requests获取网络资源,参看另一篇文章,比较简单Python 网络开发基础之Requests_Jiangugu的博客-CSDN博客_requests技术
更新说明:因爬虫可能涉及网站敏感信息,本文对网站名都替换成xx,截图里网站名都已擦除。但不影响本文中方法的使用。
BS实际就是将网页元素封装在一个类里,通过调用类的方法和属性可以方便地提取元素。在一些复杂的爬虫里,一般使用xpath或css。但BS使用起来相对更简单些。
import requests
from bs4 import BeautifulSoup
headers = {'User-Agent': "通过你的浏览器可以获取"}
request = requests.get("https://movie.xx.com/top250", headers=headers)
# 解析
soup = BeautifulSoup(request.content, features="html.parser")
BS在解析网页的时候,需要指定解析器。html.parser是自带的,还可以安装lxml、xml、html5lib等解析器。对应的网页元素如下:
1、BS提供的查找元素的方法
有了bs对象,就可以通过其提供的方法和属性抽取网页中我们想要的元素。bs对象提供的方法有
方法名 | 解释 |
find | 搜索一个 |
find_all | 搜索全部 |
find_parent | 在父节点中搜索一个 |
find_parents | 在父节点中搜索全部 |
find_next_sibling/find_next_siblings | 搜索下一个/后面全部同级节点 |
find_previous_sibling/find_previous_siblings | 搜索上一个/前面全部同级节点 |
我们以find方法为例,获取第一个推荐电影的名字。通过查看元素可以,电影名字包裹在一个<span>电影名字</span>里,且class属性为title。
result = soup.find('span', class_='title')
print(result.get_text())
# 输出:'肖申克的救赎'
我们在查找元素时,为了快速定位,往往会通过直接指定一些属性。如指定class和id。但如name属性,因find方法有一个name参数,所以不能试用name='xxx'这种方式,这里的name参数指的是标签tag的名字。因此,所有不能直接指定的属性,都可以通过字典形式包装一下,传给attrs参数
# 错误方式
soup.find('a', name="docDownloadStartTime").span.string
# 正确方式
soup.find('a', attrs={'name': "docDownloadStartTime"}).span.string
find方法返回的是bs4.element.Tag类型的数据,因此,可在这个元素位置继续调用上述方法。比如获取下一个同级节点的内容,同样可以指定属性。
print(result.find_next_sibling(class_='title').get_text())
# 输出:'\xa0/\xa0The Shawshank Redemption'
2.直接通过属性查找
tag=soup.div | 可以直接通过这种方式访问元素 |
tag.name | 标签名字,如div |
tag.attrs | 标签所有属性,字典形式返回 |
tag.string | 非属性字符串,<>提取这部分内容</> |
# 获取网页中第一个a标签
tag = soup.a
tag
Out[1]: <a class="nav-login" href="https://accounts.xx.com/passport/login?source=movie" rel="nofollow">登录/注册</a>
tag.name
Out[2]: 'a'
tag.attrs
Out[3]:
{'href': 'https://accounts.xx.com/passport/login?source=movie',
'class': ['nav-login'],
'rel': ['nofollow']}
tag.string
Out[4]: '登录/注册'
当然,这里的tag也是一个bs.element类型,因此可以调用第一部分提到的查找方法。同样,通过查找方法获得的对象也可以进一步调用name,attrs,string等属性。
result.attrs
Out[5]: {'class': ['title']}
tag = tag.find_next('a')
tag
Out[6]: <a class="lnk-xxapp" href="https://www.xx.com/xxapp/app?channel=top-nav">下载xx客户端</a>
3.遍历方法
通过上面讲的方法,我现在定位到这里
tag = soup.find('div', class_='hd')
tag
Out[7]:
<div class="hd">
<a class="" href="https://movie.xx.com/subject/1292052/">
<span class="title">肖申克的救赎</span>
<span class="title"> / The Shawshank Redemption</span>
<span class="other"> / 月黑高飞(港) / 刺激1995(台)</span>
</a>
<span class="playable">[可播放]</span>
</div>
属性名 | 解释 |
tag.contents | 返回子节点列表 |
tag.children | 子节点生成器 |
tag.descendants | 子孙节点生成器 |
parents | 上一级标签生成器(parent返回一个父标签) |
tag.next_siblings | 后续所有同级标签生成器 |
tag.previous_siblings | 前续所有同级标签生成器 |
for i in tag.children:
print(i)
# 输出:
<a class="" href="https://movie.xx.com/subject/1292052/">
<span class="title">肖申克的救赎</span>
<span class="title"> / The Shawshank Redemption</span>
<span class="other"> / 月黑高飞(港) / 刺激1995(台)</span>
</a>
<span class="playable">[可播放]</span>
综合运用上述方法,可以很简单地就能实现对网页元素地解析提取。但很多时候当网页结构比较复杂,而我们又只想提取少量特定元素时,直接使用xpath或css可能会更方便直接。