beautifulSoup的讲解
一个简单的例子:
from urllib.request import urlopen
from bs4 import BeautifulSoup
from urllib.error import HTTPError
html=urlopen("http://www.pythonscraping.com/pages/warandpeace.html")
bsObj= BeautifulSoup(html)
alltext=bsObj.findall(id="text")
print(alltext[0].get_text())
find()和findAll()
例如,下面两行代码是完全一样的: bsObj.findAll(id=“text”)
bsObj.findAll("", {“id”:“text”})
假如你运行下面的代码, Python 就会因为你误用 class 保留字而产生一个语法错误:
bsObj.findAll(class=“green”)
不过,你可以用 BeautifulSoup 提供的有点儿臃肿的方案,在 class 后面增加 一个下划线:
bsObj.findAll(class_=“green”)
另外,你也可以用属性参数把 class 用引号包起来:
bsObj.findAll("", {“class”:“green”})
其他BeautifulSoup对象:
NavigableString 对象 用来表示标签里的文字,不是标签(有些函数可以操作和生成 NavigableString 对象, 而不是标签对象)。
Comment 对象 用来查找 HTML 文档的注释标签
导航树
以该网站为例:
http://www.pythonscraping.com/pages/page3.html
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xkEbL7mM-1646223062709)(images/image-20220228094324927.png)]
#区分children()和descendants()函数的区别
from urllib.request import urlopen
from bs4 import BeautifulSoup
from urllib.error import HTTPError
html=urlopen("http://www.pythonscraping.com/pages/page3.html ")
bsObj= BeautifulSoup(html)
for child in bsObj.find("table",{"id":"giftList"}).children:
print(child)
for descendant in bsObj.find("table",{"id":"giftList"}).descendants:
如果你只想找出子标签,可以用 .children 标签:
如果你用 descendants() 函数而不是 children() 函数,那么就会有二十几个标签打印出来,包括 img 标签、span 标签,以及每 个 td 标签。
#处理兄弟结点的标签
for sibling in bsObj.find("table",{"id":"giftList"}).tr.next_siblings:
print(sibling)
这段代码会打印产品列表里的所有行的产品,第一行表格标题除外。
#父类标签处理:
from urllib.request import urlopen
from bs4 import BeautifulSoup
from urllib.error import HTTPError
html=urlopen("http://www.pythonscraping.com/pages/page3.html ")
bsObj= BeautifulSoup(html)
print(bsObj.find("img",{"src":"../img/gifts/img1.jpg"}).parent.previous_sibling.get_text())
#这段代码会打印 ../img/gifts/img1.jpg 这个图片对应商品的价格(这个示例中价格是$15.00)。
正则表达式:
可以去 RegexPal(http://regexpal.com/)这类网站上在线测试 正则表达式。
符 号 | 含 义 | 例 子 | 匹配结果 |
---|---|---|---|
* | 匹配前面的字符、子表达式或括号里的字符 0 次 或多次 | a * b * | aaaaaaaa,aaabbbbb, bbbbbb |
+ | 匹配前面的字符、子表达式或括号里的字符至少 1 次 | a+b+ | aaaaaaab,aaabbbbb, abbbbbb |
[] | 匹配任意一个字符(相当于“任选一个”) | [A-Z]* | APPLE,CAPITALS, QWERTY |
() | 表达式编组(在正则表达式的规则里编组会优先 运行) | (ab) | a a a b a a b,a b a a a b, ababaaaaab |
{m,n} | 匹配前面的字符、子表达式或括号里的字符 m 到 n 次(包含 m 或 n) | a{2,3}b{2,3} | aabbb,aaabbb,aabb |
[^] | 匹配任意一个不在中括号里的字符 | [^A-Z]* | a p p l e,l o w e r c a s e, qwerty |
| | 匹配任意一个由竖线分割的字符、子表达式(注 意是竖线,不是大字字母 I) | b(a|i|e)d | bad,bid,bed |
. | 匹配任意单个字符(包括符号、数字和空格等) | b.d | bad,bzd,b$d,b d |
^ | 指字符串开始位置的字符或子表达式 | ^a | apple,asdf,a |
\ | 转义字符(把有特殊含义的字符转换成字面形式) | \ . \ | \ \ | .|\ |
$ | 经常用在正则表达式的末尾,表示“从字符串的 末端匹配”。如果不用它,每个正则表达式实际都 带着“.*”模式,只会从字符串开头进行匹配。这 个符号可以看成是 ^ 符号的反义词 | [A-Z] * [a-z] * $ | ABCabc,zzzyx,Bob |
?! | “不包含”。这个奇怪的组合通常放在字符或正则 表达式前面,表示字符不能出现在目标字符串里。 这个符号比较难用,字符通常会在字符串的不同 部位出现。如果要在整个字符串中全部排除某个 字符,就加上 ^ 和 $ 符号 | ^((?![A-Z]).)*$ | no-caps-here,$ymb0ls a4e f!ne |
#例如:打印所有照片的相对路径:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
from urllib.error import HTTPError
html=urlopen("http://www.pythonscraping.com/pages/page3.html ")
bsObj= BeautifulSoup(html)
images=bsObj.findAll("img",{"src":re.compile("\.\.\/img\/gifts\/img.*\.jpg")})
for image in images:
print(image)
#结果:
<img src="../img/gifts/img1.jpg"/>
<img src="../img/gifts/img2.jpg"/>
<img src="../img/gifts/img3.jpg"/>
<img src="../img/gifts/img4.jpg"/>
<img src="../img/gifts/img6.jpg"/>
Process finished with exit code 0
##只提取地址
for image in images:
print(image["src"])
#结果:
<img src="../img/gifts/img1.jpg"/>
<img src="../img/gifts/img2.jpg"/>
<img src="../img/gifts/img3.jpg"/>
<img src="../img/gifts/img4.jpg"/>
<img src="../img/gifts/img6.jpg"/>
Process finished with exit code 0
lambda表达式
soup.findAll(lambda tag: len(tag.attrs) == 2)
下面的代码就是获取有两个属性的标签:
print(bsObj.findAll(lambda tag: len(tag.attrs) == 2))