@songying
2020-07-23T15:58:54.000000Z
字数 3642
阅读 2112
python爬虫
尝试换个解析器
lxml
html.parser
pip install beautifulsoup4
from bs4 import BeautifulSoup # 导入BeautifulSoup
当你爬取下HTML文本之后,你要做的第一件事就是将其解析成BeautifulSoup对象,这样才能进行后续分析。
soup = BeautifulSoup( "html语句","lxml")
BeautifulSoup 对象表示的是一个文档的全部内容
soup.prettify() # 格式化输出html内容
我们就来爬取简书上的一篇文章为例:
import requests
from bs4 import BeautifulSoup
response = requests.get('https://www.jianshu.com/p/0f5dc1d3d406')
soup = soup = BeautifulSoup(response.text,"lxml")
soup.prettify()
你自己查看输出,看看是不是HTML代码。
在前面我们提到了Beautiful Soup对象,这里我们详细探讨一下Beautiful Soup中的对象种类。
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag , NavigableString , BeautifulSoup , Comment .
Tag对象指的就是HTML代码中的 h1,
p,
body 等标签,在下面中就是一段HTML代码,其中的meta
就是一个Tag 。
<meta content="title: 少年,想不想搭建一个属于自己的博客 date: 2017-10-19 17:04:12" name="description"/>
此外,tag的属性操作方法与python中的字典一样。
tag = soup.标签名 # 如p,title等,查找的时第一个符合要求的标签
tag对象有两个属性,分别时name属性和attrs属性
- name属性:
tag.name
,输出值为标签本身(title,p)- attrs属性: tag.attrs
一个tag,attrs
会有多个子属性,诸如在HTML中提到的有class
, id
, style
, title
等属性。
tag.attrs # 显示所有属性
tag['属性名'] # 获取单一属性
tag.get('属性名') # 获取单一属性
tag['id'] = 1 # 修改属性
del tag['id'] # 删除属性
该对象用来表示Tag对象中的文字.
tag_name.string # 获取标签中的内容,类型为NavigableString
unicode_string = unicode(tag.string) # 将 NavigableString 对象转换成Unicode字符串
tag.string.replace_with("更改后的内容") # 更改tag中打内容
BeautifulSoup 对象表示的是一个文档的全部内容,可以将它想象成一个特殊的tag。一般情况下只会用到格式化输出soup.prettify()
,以及后面的find()
与find_all
函数。
总的来说,你把它当成Tag对象就行。
Comment对象 表示的是HTML文件中的注释部分。
<!-- 注释内容 -->
Comment 对象是一个特殊类型的 NavigableString 对象。我们并不需要注释内容,所以我们需要在处理前判断某段文字是否属于注释内容。
if type(soup.tag_name.string) == bs4.element.Comment
无论是tag对象还是Beautifulsoup对象都可以通过.tag_name
来访问它的子节点,不理解的话可以参见官方文档的 遍历文档树 -> 子节点 一节。
过滤器顾名思义就是过滤信息的容器,通常与下面两个查找函数组合起来筛选出我们想要的信息。过滤器可以被用在tag的name中,节点的属性中,字符串中或他们的混合中.
过滤器有以下几种类型:
字符串
在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容
soup.find_all('b') # 查找文档中所有的<b>标签
正则表达式
如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的
match()
来匹配内容.
soup.find_all(re.compile("^b"))找出所有以b开头的标签
列表
如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.
soup.find_all(["a", "b"])# 查找文档中所有<a>标签和<b>标签
True
True
可以匹配任何值
soup.find_all(True) # 查找所有tag
方法
如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回
True
表示当前元素匹配并且被找到,如果不是则反回False
# 校验了当前元素,如果包含 class 属性却不包含 id 属性,那么将返回 True
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
soup.find_all(has_class_but_no_id)
- 函数功能: 搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件.
- 返回值: 没找到返回空列表,找到返回包含tag信息的列表
html.find_all( name , attrs , recursive , text ,limit, keywords )
name参数:
可以查找所有名字为 name 的tag, 可以是任意类型过滤器,字符串,正则,列表,方法,True。
soup.find_all("title") # 查找tag名为title的tag
attrs参数
有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:
data_soup.find_all(data-foo="value")
# SyntaxError: keyword can't be an expression
但是可以通过
find_all()
方法的attrs
参数定义一个字典参数来搜索包含特殊属性的tag:
data_soup.find_all(attrs={"data-foo": "value"})
keyword参数:
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索,如果包含一个名字为
id
的参数,Beautiful Soup会搜索每个tag的”id”属性.
soup.find_all(id='link2') # 查找属性内容中id='link2'的tag
其中,属性内容可以使用过滤器,字符串,正则,列表,方法,True。
soup.find_all(href=re.compile("elsie")) # 查找属性内容中属性herf中包含elsie的tag
可以使用多个制定名字的参数来过滤tag:
soup.find_all(href=re.compile("elsie"), id='link1')
在tag的属性中,有一个常用的属性
class
,但由于与python关键字冲突,因此使用class_
来代替class
作为搜索时候的属性描述。
soup.find_all("a", class_="sister") # 搜索所有class内容为sister的a
class_
参数同样接受不同类型的过滤器
,字符串,正则表达式,方法或True
recursive参数
- false:只搜索tag的直接子节点
- true: 搜索tag的所有子孙节点(默认)
text参数
通过
text
参数可以搜搜文档中的字符串内容,text参数接受字符串,正则,列表,True。
soup.find_all("a", text="Elsie") # 找到string内容中包含Elsie的a
limit参数:
limit
参数限制返回结果的数量.
soup.find_all("a", limit=2)
find(name, attrs, recursive, text, keywords)
# 返回值: 没找到: None
find()
相当于limit = 1
的findAll(),唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.
其实,你只要掌握了上述内容,基本可以应付大多数爬虫,这就是典型的掌握20%,解决80%
.