Python官方文档都说自己解析XML的方式存在漏洞了,那我也只能用他推荐的了。
这里我使用的BeautifulSoup,因为其中文文档十分完整清晰,而且相比于defusedxml,它不仅可以解析XML还可以解析HTML,非常方便。文档地址
另外,如果是简单的网页解析任务,可以直接将获取到的网页进行正则表达式匹配也可以达到效果,只是可能会出现各种编码各种错误问题。
更新: 现在requests
开发者新建了一个项目叫做requests-html
,目的是提供比BeautifulSoup
更好的性能和更好用的API。
Installation
1 | 直接apt安装 |
基本概念
TAG:表示xml/html里面的一个元素(节点),包括标签以及其里面的内容
基本使用
最简单的使用例子:
1 | import urllib.request |
查找
1 | # 查找标签 |
获取内容
1 | tag.name # 如果是Tag,那么返回它本身,例如,如果是a标签,那就返回a;如果是soup对象,那么返回[document],返回值都是str类型 |
操作
1 | tag.string = '' # 修改标签内部的字符串 |
遍历
获取tag内的字符串用tag.string
,可以通过unicode方法将NavigableString对象转换成Unicode字符串,如unicode_st
ring = unicode(tag.string)
TroubleShooting
- 如果出现无法找到某些真的存在的标签,可能原因是选择的解析器有问题,可以将lxml换成html5lib
如果要获取xml/html中的注释使用Comment对象,如
1 | markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>" |
通过点去属性的方式只能获得当前名字的第一个tag,如果要得到所有的就用soup.find_all(‘a’)
tag的.contents属性可以将tag的子节点以列表的方式输出(包括子节点的所有内容)
1 | head_tag = soup.head |
BeautifulSoup对象本身一定会包含子节点,也就是说标签也是该对象的子节点,如 soup.contents[0].name就是html
通过tag的.children生成器,可以对tag的子节点进行循环:
1 | for child in title_tag.children: |
。desendants属性可以对所有tag的子孙节点进行递归循环
1 | for child in head_tag.descendants: |
如果tag只有一个NavigableString类型的子节点,就可以用title_tag.string访问子节点
如果tag包含多个字符串就用.strings来循环,如:
1 | for string in soup.strings: |
使用soup.stripped_strings代替soup.strings可以去掉空白或空行项
父节点就正好相反了,.parent得到父节点,.parents递归得到元素的所有父节点
兄弟节点:.next_sibling,.previous_sibling来访问,通过.next_siblings和.previous_siblings属性对
当前节点的兄弟节点迭代输出for sibling in soup.a.next_siblings:这样子
回退和前进:.next_element和.previouw_element,.next_elements和.previous_elements
查找
find和find_all,还可以传入正则表达式,如soup.find_all(re.compile(“^b”))如果传入的是列表,将会与列表中任一元素匹配
的内容返回,true可以匹配任何标签,如soup.find_all(True)
检查是否包含属性tag.has_attr(‘class’)
find_all( [name](http://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh
.html#id32) , [attrs](http://www.crummy.com/software/BeautifulSoup/bs4/doc/ind
ex.zh.html#css) , [recursive](http://www.crummy.com/software/BeautifulSoup/bs4
/doc/index.zh.html#recursive “Link:
http://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#recursive"
) , [text](http://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#
text) , [**kwargs](http://www.crummy.com/software/BeautifulSoup/bs4/doc/index.
zh.html#keyword) )
attr表示具有该属性的name标签,text可以搜索非标签的字符串内容,如soup.find_all(text=”wang”)
1 | soup.find_all(id="link2")[<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>] |
limit参数:find_all()方法返回全部的搜索结果,如果文档数很大那么搜索会很慢,如果不需要全部结果,可以用limit参数,类似于SQL中的limi
t,如soup.find_all(“a”, limit=2)
如果只搜索直接子节点,就加上recursive=False参数
可以不用指明find_all,如soup.find_all(“a”)可以用soup(“a”)代替,soup.title.find_all(text=True
)可以用soup.title(text=True)代替
其他功能,按CSS搜索、支持CSS选择器,支持修改文档树
find()方法至返回一个,其他的还有find_parents()和find_parent(),find_next_siblings(),find_next
_sibling(),find_previous_siblings(),find_previous_sibling(),find_all_next(),fi
nd_next(),find_all_previous(),find_previous()
如果只想得到tag中包含的文本内容,那么就可以用get_text()方法,获取到tag包含的所有文本内容包括子孙tag中的内容
注:beautifulsoup会自动将tag变为小写,只有添加”xml”选项才能大小写敏感,因为不指定就默认是html,html的标签对大小写不敏感,所以推
荐还是把lxml XML解析器安上,不过要先弄上什么C语言库
修改
1 | # 删除当前节点 |