一.什么是爬虫(Web Crawler)
1.概念:
爬虫是1段自动抓取互联网信息的程序,用于从互联网上抓取有价值的信息
分为定向爬虫(只抓取目标网站上的信息)和非定向爬虫(没有针对性,所有链接都爬取)这2种
2.基本原理:
①向指定地址发送请求,然后下载该页面
②用正则表达式进行匹配,筛选出需要的内容
3.实例:
import requests,bs4
response=requests.get("https://www.autohome.com.cn/all/#pvareaid=3311230")
response.encoding=response.apparent_encoding
soup=bs4.BeautifulSoup(response.text,features="html.parser")
target=soup.find(id="auto-channel-lazyload-article")
li_list=target.find_all("li")
for obj in li_list:
i=obj.find("a")
if i:
print(i.find("h3").text)
二.Requests模块
官方文档:http://cn.python-requests.org/zh_CN/latest/user/quickstart.html#id4
1.介绍:
Python内置了urllib/urllib2/httplib等模块供Http请求使用.但是,这些模块的API难以使用,需要大量的工作来完成1个简单的任务
Requests是使用Apache2 Licensed的基于Python开发的HTTP库,其在Python内置模块的基础上进行了高度封装,使得进行网络请求的操作
得到了极大简化.使用Requests可以轻易完成浏览器可有的任何操作
2.基本方法:
更多实例参见:https://www.cnblogs.com/wupeiqi/articles/6283017.html
关于User-Agent参数参见:https://www.jianshu.com/p/c5cf6a1967d1
关于参数json和data参见:https://blog.csdn.net/Mr_know/article/details/107002686
#以下发送各种请求的方法均是在调用此方法:
<re>=requests.request("<method>","<url>"[,params=None,data=None,json=None,headers=None,cookies=None,files=None,auth=None,timeout=None,allow_redirects=True,proxies=None,verify=True,stream=False,cert=None])
method:请求方法;为str,如"get"/"post"
#如requests.request("get","<url>")相当于requests.get("<url>")
url:指定URL;为str
#也可以写成关键字参数url
以下参数为 二.3 部分中**kwargs参数可能的取值:
params指定在URL中传递的参数(即以GET形式提交的数据)
#为dict/list/tuple/bytes(只能包含ASCII中的字符)/str(可以包含ASCII中没有的字符)
data指定在请求体中传递的数据(即以POST形式提交的数据)
#为dict/list/tuple/bytes/str/file;通常使用dict形式
#在发送前都会被转换成str的形式再编码,不论传入什么形式
#data中的键/值只能是str/num/list;如果是dict,则只发送键而不发送值
json也指定在请求体中传递的数据,不过会自动转换为json的格式(即json.dumps())
#Django通过请求头中的Content-Type来确定请求体中的数据格式(json或str),再进行相应的处理
#json对应的请求头信息是{"Content-Type":"application/json"}
#如果参数中的键/值是dict(即参数中嵌套了dict),只能使用json,不能用data
headers指定请求头;为dict
①Referer:访问的上1个网站
#很多网站只有在该参数是其自身时才允许登录(见下图)
#因为通过浏览器必须先访问1次才能进入登录界面
②User-Agent:通过什么工具进行的访问
cookies指定要发送的cookies(放在请求头里)
#为dict/CookieJar
files:指定要上传的文件
#为dict,格式为{"<name>":<file_obj>...}
#也可以是其他格式,详情参见源码注释
auth:指定要发送的用于HTTP Auth的用户名/密码
#为tuple,格式为<func>("<username>","<pwd>")
#func可为HTTPBasicAuth/HTTPCustomAuth/HTTPDigestAuth
#也可以通过headers定制Authentication字段来实现
timeout:超时时限(即等待Server响应的最大时长)
#为float/tuple,后者的格式为(<connect_timeout>,<read_timeout>)
allow_redirects:是否允许进行重定向跳转;为bool
proxies:指定代理的URL;为dict
#常用于绕开网站对IP的限制
verify:为bool(是否进行SSL/TLS验证)/str(指定CA bundle文件)
#为False时即使使用HTTPS也不进行验证
stream:是否采用"流"的形式接收返回的内容;为bool
#如果为True,则每次只下载一小部分;为False,则一次性下载全部
#设为True可防止内存过小时无法同时加载全部内容
cert:若为str,指定用于SSL/TLS验证的证书(.pem文件)
#HTTPS协议即使用SSL进行验证
若为tuple,同意指定上述证书,格式为("<f1>.crt","<f2>.key")
#这只是2种不同的格式,功能是相同的
#还有些证书是内置在计算机中的,不需要自己手动发送
re:Server返回的requests.models.Response对象
#这是1个字节对象
#实例1:
response=requests.request(
"post",
"http://dig.chouti.com/",
params={"k1":"v1","k2":"v2"},
#最后发送的URL相当于http://www.google.com?k1=v1&k2=v2
data="user=john&pwd=123",
#即使此处传入的是dict,也会先转换成如上的str形式并编码,然后再发送
json={"user":"john","pwd":"123"},
#会自动转换成json格式而不会转换成如上的str形式
headers={
"Referer":"http://dig.chouti.com/"
#很多网站都被设置为只有本参数(即访问的上1个网站)是其自身的时候才允许登录
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36"
#说明是通过Chrome浏览器进行的该访问
},
file={
"f1":open("s1.py","wb"),
#f1是自定义的key;在Server使用的文件名是s1.py
"f2":("sc1.py",open("s2.py","wb"))
#sc1.py是在Server使用的文件名
},
auth=HTTPBasicAuth("smith","123123"),
#相当于在headers中增加"Authentication":_basic_auth_str("smith","123123")
proxies={
"http":"http://4.19.128.5:8099"
#所有HTTP请求都通过该代理进行
}
)
#实例2(关于stream参数):
from contextlib import closing
with closing(requests.get('http://httpbin.org/get', stream=True)) as r:
for i in r.iter_content():#在此处理响应,每次循环只接收一小部分
print(i)
3.发送请求:
<re>=requests.get("<url>",params=None[,**kwargs]):发送GET请求
#参数说明:同requests.request()
#无参实例:
>>> re=requests.get("https://www.autohome.com.cn/beijing/")
>>> print(re)
<Response [200]>
>>> print(type(re))
<class 'requests.models.Response'>
>>> re.encoding=re.apparent_encoding
#.encoding指定使用的解码方式;.apparent_encoding表示原数据使用的编码方式
>>> print(re.text)#这里只截取了结果中间部位的一小部分
#.text表示对象中的文本内容
...
<div id="auto-header" class="topbar">
<div id="auto-header-inner" class="topbar-inner">
<!-- mini begin -->
<div class="topbar-mini">
<div class="mini-main">
...
>>> print(type(re.text))
<class 'str'>
#有参实例:
>>> import requests
>>> payload={'key1': 'value1', 'key2': 'value2'}
>>> re=requests.get("http://httpbin.org/get",params=payload)
>>> print(re)
<Response [200]>
>>> print(re.text)
{
"args": {
"key1": "value1",
"key2": "value2"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.24.0",
"X-Amzn-Trace-Id": "Root=1-5f202eb1-72b8d5fcb6f97326b8e295fc"
},
"origin": "111.192.245.200",
"url": "http://httpbin.org/get?key1=value1&key2=value2"
}
>>> print(re.url)
http://httpbin.org/get?key1=value1&key2=value2
###############################################################################################################
<re>=requests.post("<url>",data=None,json=None[,**kwargs]):发送POST请求
#参数说明:同requests.request();data和json应至少使用1个
#不指定请求头的实例:
>>> import requests
>>> payload={'key1': 'value1', 'key2': 'value2'}
>>> print(re.text)
{
"args": {},
"data": "",
"files": {},
"form": {
"key1": "value1",
"key2": "value2"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "23",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "python-requests/2.24.0",
"X-Amzn-Trace-Id": "Root=1-5f2031ba-8d79bd8105cf3c5b5fd43a5d"
},
"json": null,
"origin": "111.192.245.200",
"url": "http://httpbin.org/post"
}
>>> print(re.content)
b'{\n "args": {}, \n "data": "", \n "files": {}, \n "form": {\n "key1": "value1", \n "key2": "value2"\n }, \n "headers": {\n "Accept": "*/*", \n "Accept-Encoding": "gzip, deflate", \n "Content-Length": "23", \n "Content-Type": "application/x-www-form-urlencoded", \n "Host": "httpbin.org", \n "User-Agent": "python-requests/2.24.0", \n "X-Amzn-Trace-Id": "Root=1-5f2031ba-8d79bd8105cf3c5b5fd43a5d"\n }, \n "json": null, \n "origin": "111.192.245.200", \n "url": "http://httpbin.org/post"\n}\n'
#指定请求头的实例:
>>> import requests,json
>>> url='http://httpbin.org/post'
>>> data={'some':'data'}
>>> headers={'content-type':'application/json'}
>>> re=requests.post(url,data=json.dumps(payload),headers=headers)
>>> print(re.text)
{
"args": {},
"data": "{\"key1\": \"value1\", \"key2\": \"value2\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "36",
"Content-Type": "application/json",#手动指定的请求头信息
"Host": "httpbin.org",
"User-Agent": "python-requests/2.24.0",
"X-Amzn-Trace-Id": "Root=1-5f203333-c3e163e8e9bfd0b8928f020a"
},
"json": {
"key1": "value1",
"key2": "value2"
},
"origin": "111.192.245.200",
"url": "http://httpbin.org/post"
}
>>> print(re.cookies)
<RequestsCookieJar[]>
###############################################################################################################
requests.put("<url>",data=None[,**kwargs]):发送put请求
requests.head("<url>"[,**kwargs]):发送head请求
requests.delete("<url>"[,**kwargs]):发送delete请求
requests.patch("<url>",data=None[,**kwargs]):发送patch请求
requests.options("<url>"[,**kwargs]):发送options请求
4.Cookie的自动管理:
<s>=requests.session()/<s>=requests.Session()
#注:requests.Session是1个类,requests.Session()是该类的1个实例
#requests.session()则是1个方法,功能是返回上述类的1个实例,而不做其他任何操作(见下图)
#参数说明:
s:返回的requests.Session类的1个实例
<s>.<type>():发送指定类型的请求
#参数说明:
type:通过<s>调用模块中的各个方法,以发送不同类型的请求
#可为get/post/put/patch/head/options/delete
通过以上2个方法实现Cookies/Headers的自动管理,即自动获取/发送Cookies/Headers而不用手动添加
5.属性:
示例参见:https://www.cnblogs.com/wupeiqi/articles/6283017.html
<re>.headers:返回响应头
#参数说明:
re:发送请求后Server返回的requests.models.Response对象(是字节)
#######################################################################
<re>.encoding[="<coding>"]:查看或设置Response对象的编码方式
<re>.apparent_encoding:返回re使用的编码方式
#这2种方式的区别在于:前者通过请求头得到,后者通过内容分析得到,通常以前者为准
#参数说明:
coding:指定用什么格式进行解码
#因为re本质上是字节数据,要得到.text需要进行解码
#######################################################################
<re>.text:Response对象的内容,以文本格式返回
<re>.content:Response对象的内容,以二进制格式返回
#######################################################################
<re>.status_code:状态码
#如200(访问成功),3xx(重定向)
#######################################################################
<re>.cookies:返回的Cookies
<re>.cookies.get_dict():返回Cookies构成的dict
#######################################################################
<re>.url:进行了响应的页面的URL
#如:如果进行了重定向,会返回重定向到的页面的URL,而不是请求的页面的URL
#实例:
>>> re=requests.get("https://www.autohome.com.cn")
>>> re.url
'https://www.autohome.com.cn/beijing/'
三.Beautifulsoup模块
官方文档:https://www.crummy.com/software/BeautifulSoup/
1.功能:
BeautifulSoup该模块用于接收1个HTML/XML str并对其进行格式化,之后可以使用该模块提供的其他方法快速查找其中的指定元素,从而使
得在HTML/XML中查找指定元素变得简单
2.安装
(1)安装本模块:
pip install bs4
(2)安装第3方解析器:
pip install lxml
pip install html5lib
3.对象
(1)进行格式化(创建BeautifulSoup对象):
<soup>=BeautifulSoup(<HText>[,features="html.parser"]):对HTML/XML文本进行格式化
#即将str转换成对象(如标签)
#参数说明:
HXText:要进行转换的HTML/XML文本
#通过type()查看得到的结果应为str
features:指定使用什么解析器进行转换(可用的解析器见下图)
#也可以作为第2个位置参数传入
#即使使用html.parser,也最好显式指明,否则有的IDE(如Pycharm)会发出警告
soup:返回转换后得到的bs4.BeautifulSoup对象
#最外层是1个<HTML>,其中嵌套着<head>和<body>,再其中继续嵌套
#实例:
import requests,bs4
>>> re=requests.get("https://www.autohome.com.cn/beijing/")
>>> print(type(re))
<class 'requests.models.Response'>
>>> re=requests.get("https://www.autohome.com.cn/beijing/")
>>> print(re)
<Response [200]>
>>> print(type(re))
<class 'requests.models.Response'>
>>> re.encoding=re.apparent_encoding#表示原数据使用的编码方式
>>> print(re.text)#这里只截取了结果中间部位的一小部分
...
<div id="auto-header" class="topbar">
<div id="auto-header-inner" class="topbar-inner">
<!-- mini begin -->
<div class="topbar-mini">
<div class="mini-main">
...
>>> soup=bs4.BeautifulSoup(re.text,features="html.parser")
>>> print(soup)#这里只截取了结果中间部位的一小部分
...
<script type="text/javascript">
var _ahs = _ahs || {};
window._ahs = _ahs;
(function() {
if (typeof(pvTrack) !== "undefined") {
...
>>> print(type(soup))
<class 'bs4.BeautifulSoup'>
#注意:
1.推荐使用lxml,因为效率更高
2.在Python2.7.3/Python3.2.2前的版本,必须安装lxml/html5lib,因为这些Python版本的标准库中内置的HTML解析方法不够稳定
3.如果一段HTML/XML文档格式不正确,那么在不同的解析器中返回的结果可能不同
(2)Tag对象:
<tag>=bs4.element.Tag(name="<tagtype>"[,attrs={"<attr1>":"<v1>"...}]):创建Tag对象
#参数说明:
tagtype:指定标签类型,如"li"/"div";为str
attrs:指定标签的属性及该属性的值;均为str
#不能把每个属性都写成关键字参数的形式
tag:返回创建的Tag对象
#实例:
>>> bs4.element.Tag(name="a",attrs={"id":"123"})
<a id="123"></a>
4.方法
更多实例参见:https://www.cnblogs.com/wupeiqi/articles/6283017.html
(1)查找标签:
<mtag>=<tos>.find(["<tagtype>",attrs={"<attr1>":"<v1>"...},recursive=True,text=None]):返回<tos>中第1个符合规则的标签
<mtag_li>=<tos>.find_all(["<tagtype>",attrs={"<attr1>":"<v1>"...},recursive=True,text=None]):返回<tos>中所有符合规则的标签
#参数说明:
tos:指定在哪个对象中进行匹配
#为bs4.BeautifulSoup对象/bs4.element.Tag对象
tagtype:指定标签类型,如"li"/"div";为str
#也可写成关键字参数name="<tagtype>"
#也可以使用["<tagtype1>","<tagtype2>"...]的形式(或写成关键字参数),用于同时查找多个类型的标签(即各类型间的关系是[或])
#另外,name属性还支持使用正则表达式/函数进行筛选
attrs:指定标签的属性及该属性的值(用于筛选);均为str
#如:attrs={"id":"container","nid":"11111"}
#也可以写成<attr1>="<v1>",<attr2>="v2"...的形式
#注意:写成关键字形式时class属性应写为class_="<v1>",否则会和用于定义类的关键字(class)重复
#所有这些属性都可以写成类似于<tagtype>的列表形式来进行筛选
recursive:是否递归地进行查找;为bool
#如果为False,则只查找直接子标签(即<soup>中最外层的标签,通常是<html>)
text:指定标签中的文本内容(用于筛选);为str
#通常直接写在attrs中
mtag:返回匹配成功的标签
#如果匹配成功则是bs4.element.Tag对象
#如果没有匹配成功则是NoneType对象(即None)
mtag_li:返回匹配成功的标签构成的list
#无论匹配成功与否都是bs4.element.ResultSet对象,为类list对象
#然后通过循环/索引获得标签对象
#实例:接 三.3
>>> soup1=soup.find(id="hotcar-1")
>>> print(type(soup1))
<class 'bs4.element.Tag'>
>>> soup11=soup1.find(id="content")
>>> print(soup11)
None
>>> print(type(soup11))
<class 'NoneType'>
>>> soup12=soup1.find("a")
>>> print(type(soup12))
<class 'bs4.element.Tag'>
>>> print(soup12)
<a href="/suv/#pvareaid=3311952">SUV</a>
>>> soup13=soup1.find_all("a")
>>> print(soup13[0])#打印soup13中的第1个元素
<a href="/suv/#pvareaid=3311952">SUV</a>
>>> soup131=soup13[0].find_all("a")#soup13没有.find_all方法,soup13[0]才有
>>> print(soup131)
[]
>>> import re
>>> rep=re.compile("^p")
>>> print(soup.find(name=rep))
<path d="M19.023 19.6l.114-.417.41-.138a2.791 2.791 0 0 0 1.89-2.898l-.246-2.7a2.785 2.785 0 0 0-1.195-2.045l-.29-.2-.051-.347-.003-.018-.95-5.696A2.79 2.79 0 0 0 15.95 2.81h-8.3a2.79 2.79 0 0 0-2.752 2.331l-.95 5.696-.002.018-.052.348-.29.2a2.785 2.785 0 0 0-1.195 2.044l-.245 2.7a2.79 2.79 0 0 0 1.89 2.899l.409.137.114.417a1.891 1.891 0 0 0 3.606.13l.19-.54h6.853l.191.54a1.891 1.891 0 0 0 3.606-.13z"></path>
>>> print(soup.find(name="^p"))#写成位置参数也可
#注意:必须通过re.compile()生成匹配对象才能使用正则表达式,否则"^p"仍会被视为标签类型
None
>>> def func(tag):
... return tag.has_attr('class') and tag.has_attr('id')
...
>>> print(soup.find(func))#也可以写成关键字参数
<div class="topbar" id="auto-header">
...#此处省略了一部分
<!-- club pop end -->
</div>
##########################################################
<mtag_li>=<tos>.select("<selector>"[,namespaces=None,limit=None,**kwargs]):返回<tos>中所有符合规则的标签构成的list
<mtag>=<tos>.select_one("<selector>"[,namespaces=None,**kwargs]):返回<tos>中第1个符合规则的标签
#参数说明:tos同上/其他参数参见源码
selector:指定用于筛选标签的选择器(语法和JQuery中的选择器相同)
limit:指定返回的list的最大长度
#实例:接 三.3
>>> soup3=soup.select("#floornav-1")#根据id找
>>> soup31=soup3[0].select(".focus-pic")#根据class找
>>> soup311=soup31[0].select("div")#根据标签类型找
>>> soup3111=soup311[0].select("div")
>>> print(soup3111[0].text)
今日焦点
##########################################################
<tag>.find_next(["<tagtype>",attrs={"<attr1>":"<v1>"...},recursive=True,text=None]):返回下1个标签
<tag>.find_all_next(["<tagtype>",attrs={"<attr1>":"<v1>"...},recursive=True,text=None]):返回之后所有标签构成的list
<tag>.find_next_sibling(["<tagtype>",attrs={"<attr1>":"<v1>"...},recursive=True,text=None]):返回下1个同级标签
<tag>.find_next_siblings(["<tagtype>",attrs={"<attr1>":"<v1>"...},recursive=True,text=None]):返回之后所有同级标签构成的list
<tag>.find_previous(["<tagtype>",attrs={"<attr1>":"<v1>"...},recursive=True,text=None]):返回上1个标签
<tag>.find_all_previous(["<tagtype>",attrs={"<attr1>":"<v1>"...},recursive=True,text=None]):返回之前所有标签构成的list
<tag>.find_previous_sibling(["<tagtype>",attrs={"<attr1>":"<v1>"...},recursive=True,text=None]):返回上1个同级标签
<tag>.find_previous_siblings(["<tagtype>",attrs={"<attr1>":"<v1>"...},recursive=True,text=None]):返回之前所有同级标签构成的list
#之前/后指的是遍历时的顺序
#如果没有,返回None/空list
#参数说明:同<tos>.find_all()
#实例:
>>> html_doc="""<html lang="en">
... <body>
... <div>ddd</div>
... bbooddyy
... <div>
... <p>pppp</p>
... </div>
... <input>
... <a></a>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> s.find("div").find_next()
<div>
<p>pppp</p>
</div>
>>> s.find("div").find_all_next()
[<div>
<p>pppp</p>
</div>, <p>pppp</p>, <input/>, <a></a>]
>>> s.find("p").find_all_next()
[<input/>, <a></a>]
>>> s.find("p").find_all_previous()
[<div>
<p>pppp</p>
</div>, <div>ddd</div>, <body>
<div>ddd</div>
bbooddyy
<div>
<p>pppp</p>
</div>
<input/>
<a></a>
</body>, <html lang="en">
<body>
<div>ddd</div>
bbooddyy
<div>
<p>pppp</p>
</div>
<input/>
<a></a>
</body>
</html>]
>>> s.find("p").find_previous_siblings()
[]
>>> s.find("input").find_previous_sibling()
<div>
<p>pppp</p>
</div>
>>> s.find("input").find_previous_sibling().find_previous_siblings()
[<div>ddd</div>]
(2)删除内容:
<re>=<tag>.clear():清空指定标签中的所有内容
#<tag>本身不会被删除
#参数说明:
tag:为bs4.element.Tag对象
re:返回None
#实例:
>>> import requests,bs4
>>> html_doc="""<html lang="en">
... <body>
... <a>aaaaa</a>
... bbooddyy
... <div>
... <p>pppp</p>
... </div>
... <a>aa2</a>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> re=s.find("body").clear()
>>> print(s)
<html lang="en">
<body></body>
</html>
>>> print(re)
None
##########################################################
<re>=<tag>.decompose():递归地删除所有的标签
#<tag>本身也会被删除
#参数说明:
re:返回None
#实例:
>>> import requests,bs4
>>> html_doc="""<html lang="en">
... <body>
... <a>aaaaa</a>
... bbooddyy
... <div>
... <p>pppp</p>
... </div>
... <a>aa2</a>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> re=s.find("body").decompose()
>>> print(s)
<html lang="en">
</html>
>>> print(re)
None
##########################################################
<rtag>=<tag>.extract():递归地删除所有的标签,并获取被删除的标签
#参数说明:
rtag:返回被删除的标签(即<tag>)
#实例:
>>> import requests,bs4
>>> html_doc="""<html lang="en">
... <body>
... <a>aaaaa</a>
... bbooddyy
... <div>
... <p>pppp</p>
... </div>
... <a>aa2</a>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> re=s.find("body").extract()
>>> print(s)
<html lang="en">
</html>
>>> print(re)
<body>
<a>aaaaa</a>
bbooddyy
<div>
<p>pppp</p>
</div>
<a>aa2</a>
</body>
>>> print(type(re))
<class 'bs4.element.Tag'>
(3)对标签进行转换:
<tag>.encode():将指定标签转换为字节
#<tag>本身也会被转换
<tag>.encode_contents():将指定标签中的内容转换为字节
#<tag>本身不会被转换
#实例:
>>> import requests,bs4
>>> html_doc="""<html lang="en">
... <body>
... <a>aaaaa</a>
... bbooddyy
... <div>
... <p>pppp</p>
... </div>
... <a>aa2</a>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> print(s.find("div").encode())
b'<div>\n<p>pppp</p>\n</div>'
>>> print(s.find("div").encode_contents())
b'\n<p>pppp</p>\n'
##########################################################
<tag>.decode():将指定标签转换为str
#<tag>本身也会被转换;也可以使用str(<tag>)
<tag>.decode_contents():将指定标签中的内容转换为str
#<tag>本身不会被转换
#实例:接上半部分
>>> print(s.find("div").decode())
<div>
<p>pppp</p>
</div>
>>> print(s.find("div").decode_contents())
#注意:<p>pppp</p>前后各有1个换行符
<p>pppp</p>
(4)获取指定属性的值:
<v>=<tag>.get("<attr>"):返回指定标签的指定属性的值
#参数说明:
attr:指定属性;为str
v:返回tag的attr属性的值;为str
#如果<tag>没有<attr>属性,则返回None
#实例:
>>> doc="""<a href="https://www.google.com"></a>"""
>>> s=bs4.BeautifulSoup(doc)
>>> s.find("a").get("href")
'https://www.google.com'
>>> print(s.find("a").get("nid"))
None
##########################################################
<t>=<tag>.get_text():获取指定标签中的所有文本内容
#参数说明:
t:返回的文本内容;为str
#也包括子标签中的文本内容
#实例:
>>> doc="""<a href="https://www.google.com">aaaaa<div>ddd</div></a>"""
>>> s=bs4.BeautifulSoup(doc)
>>> s.find("a").get_text()
'aaaaaddd'#注意:字节点中的文本内容也会被返回
(5)检查标签是否具有指定属性:
<re>=<tag>.has_attr("<attr>"):检查指定标签是否具有指定属性
#参数说明:
re:返回检查结果;为bool
#实例:接 三.5.(1)
>>> print(s.find("a").has_attr("nid"))
False
>>> print(s.find("a").has_attr("href"))
True
(6)查找标签的索引位置:
<n>=<tag>.index(<tag2>):查找<tag2>在<tag>中的索引位置
#参数说明:
tag2:为<tag>中的某个标签
#<tag2>必须是<tag>的直接子标签才能找到其索引
n:返回<tag2>在<tag>中的索引位置
#如果<tag2>不在<tag>中,直接报错
#从1开始,且只为奇数,故索引依次为1/3/5...
#实例:
>>> html_doc="""<html lang="en">
... <body>
... <div>ddd</div>
... bbooddyy
... <div>
... <p>pppp</p>
... </div><a>aa2</a><input type="text"><b>bbb</b>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> print(tag.index(tag.find("input")))
7
>>> print(tag.index(tag.find("b")))
9
>>> print(tag.index(tag.find("div")))
1
>>> print(tag.index(tag.find("p")))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\Euler\AppData\Roaming\Python\Python37\site-packages\bs4\element.py", line 1374, in index
raise ValueError("Tag.index: element not in tag")
ValueError: Tag.index: element not in tag
>>> print(tag.index(tag.find("h2")))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\Euler\AppData\Roaming\Python\Python37\site-packages\bs4\element.py", line 1374, in index
raise ValueError("Tag.index: element not in tag")
ValueError: Tag.index: element not in tag
(7)插入/替换标签:
<tag>.append(<tag2>):在指定标签中插入标签(会插入到<tag>的最后)
#注意:①不会在标签后加上换行符 ②<tag2>会被从前原本所属的BeautifulSoup对象中删除
#参数说明:
tag2:指定要插入的标签;为bs4.element.Tag对象
#实例:
>>> html_doc="""<html lang="en">
... <body>
... <a>aaa</a>
... <div>ddd</div>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> s.find("body").append(s.find("a"))
>>> s.find("body").append("<a>aaa</a>")
>>> s
<html lang="en">
<body>
#注意:原本的<a>被删除了(实际上只是在移动标签而没有创建新标签)
<div>ddd</div> #因此通常会通过bs4.element.Tag()创建1个新的Tag对象
<a>aaa</a><a>aaa</a></body>#注意:不要直接添加tag str
</html>
##########################################################
<tag>.insert(<i>,<tag2>):在指定标签中的指定位置处插入新标签
#注意:①不会在标签后加上换行符 ②<tag2>会被从前原本所属的BeautifulSoup对象中删除
#参数说明:
i:指定插入新标签的位置的索引(或插入后<tag2>在<tag>中的索引)
#注意:索引从0开始
#实例:接.append()
>>> s.find("body").insert(0,bs4.element.Tag(name="b"))
>>> s
<html lang="en">
<body><b></b>
<div>ddd</div>
<a>aaa</a><a>aaa</a></body>
</html>
##########################################################
<tag>.insert_before(<tag2>):在指定标签前插入标签
<tag>.insert_after(<tag2>):在指定标签后插入标签
#注意:①不会在标签后加上换行符 ②<tag2>会被从前原本所属的BeautifulSoup对象中删除
#实例:接.insert()
>>> s.find("div").insert_before(bs4.element.Tag(name="h1"))
>>> s
<html lang="en">
<body><b></b>
<h1></h1><div>ddd</div>
<a>aaa</a><a>aaa</a></body>
</html>
##########################################################
<dtag>=<tag>.replace_with(<tag2>):替换指定标签
#参数说明:
tag,tag2:将用<tag2>替换<tag>
dtag:返回被替换的标签(即<tag>)
#实例:接.insert_before/after
>>> s.find("a").replace_with(bs4.element.Tag(name="h2"))
<a>aaa</a>
>>> s
<html lang="en">
<body><b></b>
<h1></h1><div>ddd</div>
<h2></h2><a>aaa</a></body>
</html>
(8)建立标签间的关系:
<tag>.setup([parent=None,previous_element=None,next_element=None,previous_sibling=None,next_sibling=None]):建立/修改<tag>与其他标签的关系
#即使修改了标签间的关系,在BeautifulSoup对象中仍然不变,只在通过相应的方法查看相应的标签时展示
#参数说明:
parent...:分别为父标签/上/下1个(同级)标签;均为Tag对象
#实例:
>>> html_doc="""<html lang="en">
... <body>
... <div>ddd<a>aaa</a></div>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> d=s.find("div")
>>> a=s.find("a")
>>> d.setup(previous_sibling=a)
>>> s
<html lang="en">
<body>
<div>ddd<a>aaa</a></div>
</body>
</html>
>>> d.find_previous_sibling()
<a>aaa</a>
(9)将标签包裹起来:
<wtag>=<tag>.wrap(<tag2>):将指定标签包裹起来
#注意:<tag2>的文本会被放在<tag>之前
#参数说明:
tag2:指定用于包裹<tag>的标签
wtag:返回包裹着<tag>的<tag2>
#实例:
>>> html_doc="""<html lang="en">
... <body>
... <div>ddd<a>aaa</a></div>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> h=bs4.element.Tag(name="h2")
>>> h.string="hhh"
>>> s.find("div").wrap(h)
<h2>hhh<div>ddd<a>aaa</a></div></h2>
>>> s
<html lang="en">
<body>
<h2>hhh<div>ddd<a>aaa</a></div></h2>
#注意:<h2>中的文本会被放在<div>之前
</body>
</html>
##############################################################
<dtag>=<tag>.unwrap():将指定标签解包
#即删除<tag>本身,但保留<tag>中的所有内容
#注意:不仅<tag>的子标签会被保留,<tag>自己的文本内容也会被保留
#参数说明:
dtag:返回被删除的标签(即不包含子标签的<tag>)
#实例:接.wrap()
>>> s.find("div").unwrap()
<div></div>
>>> s
<html lang="en">
<body>
<h2>hhhddd<a>aaa</a></h2>
</body>
</html>
>>> s.find("h2").unwrap()
<h2></h2>
>>> s
<html lang="en">
<body>
hhhddd<a>aaa</a>
</body>
</html>
5.属性:
- 可用于获取属性,也可用于设置属性
<tag>.name:获取指定标签的标签名(即标签类型)
#返回str
#参数说明:
tag:指定标签,为bs4.element.Tag对象
#实例:接 三.4.(1) 前半部分
>>> print(soup1.name)
div
>>> soup1.name="a"
>>> print(soup1.name)
a
##########################################################
<tag>.attrs:获取指定标签的所有属性构成的dict
#实例:接 三.4.(1) 前半部分
>>> print(soup13[0].attrs)#获取所有属性构成的字典
{'href': '/suv/#pvareaid=3311952'}
>>> print(soup13[0].attrs.get("href"))#获得href属性的值
/suv/#pvareaid=3311952
>>> soup13[0].attrs["kkk"]={"vvv"}#当然,原始的文档不会被修改,只有soup13会被修改
>>> print(soup13[0].attrs)
{'href': '/suv/#pvareaid=3311952', 'kkk': {'vvv'}}
>>> del soup13[0].attrs["kkk"]
>>> print(soup13[0].attrs)
{'href': '/suv/#pvareaid=3311952'}
##########################################################
<tag>.children:获得指定标签所有(直接)子节点构成的iterator
#仅包括<tag>的直接子节点,不包括孙代及之后各代标签
#节点不只包含标签,也包含文本,每2个标签间的文本都是1个节点(如果不全是空白)
<tag>.descendants:获得指定标签所有后代节点构成的iterator
#其中的元素都是完整的节点,而不是该节点去除其后代节点后剩余的部分
#实例1:
>>> import bs4
>>> html_doc="""<!DOCTYPE html>
... <html lang="en">
... <head>
... <meta charset="UTF-8">
... <title>Title</title>
... </head>
... <body>
... <a>aaaaa</a>
... bbooddyy
... <div>
... <p>pppp</p>
... </div>
... <a>aa2</a>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> re=s.find("body")
>>> print(list(re.children))
['\n', <a>aaaaa</a>, '\n bbooddyy\n ', <div>
<p>pppp</p>
</div>, '\n', <a>aa2</a>, '\n']
>>> for tag in re:
... print(tag,type(tag))
...
<class 'bs4.element.NavigableString'>#注意:标签节点和文本节点的类型不同
<a>aaaaa</a> <class 'bs4.element.Tag'>#因为可进行的操作不同
bbooddyy
<class 'bs4.element.NavigableString'>
<div>
<p>pppp</p>
</div> <class 'bs4.element.Tag'>
<class 'bs4.element.NavigableString'>
<a>aa2</a> <class 'bs4.element.Tag'>
<class 'bs4.element.NavigableString'>
#实例2:
>>> import requests,bs4
>>> html_doc="""<!DOCTYPE html>
... <html lang="en">
... <head>
... <meta charset="UTF-8">
... <title>Title</title>
... </head>
... <body>
... <a>aaaaa</a>
... bbooddyy
... <div>
... <p>pppp</p>
... </div>
... <a>aa2</a>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> re=s.find("body")
>>> print(list(re.descendants))
#进行递归,找完1个子节点中的所有后代节点再找下1个(对每个子节点的递归同理)
['\n', <a>aaaaa</a>, 'aaaaa', '\n bbooddyy\n ', <div>
<p>pppp</p>
</div>, '\n', <p>pppp</p>, 'pppp', '\n', '\n', <a>aa2</a>, 'aa2', '\n']
>>> for tag in re:
... print(tag,type(tag))
...
<class 'bs4.element.NavigableString'>
<a>aaaaa</a> <class 'bs4.element.Tag'>
bbooddyy
<class 'bs4.element.NavigableString'>
<div>
<p>pppp</p>
</div> <class 'bs4.element.Tag'>
<class 'bs4.element.NavigableString'>
<a>aa2</a> <class 'bs4.element.Tag'>
<class 'bs4.element.NavigableString'>
>>> print(list(re.descendants)[4])
<div> #注意:其中的元素都是完整的节点,而不是该节点去除其后代节点后剩余的部分
<p>pppp</p>
</div>
##########################################################
<tag>.text:返回指定标签中的文本内容(包含子标签中的内容)
#不包括标签等非文本内容
<tag>.contents:返回指定标签中的所有内容构成的list
<tag>.string:返回指定标签中的文本内容(不包含子标签中的内容)
#如果通过该属性设置标签中的文本内容,会导致<tag>的子标签被删除
<tag>.stripped_string:递归获得<tag>即其标签的文本内容
#实例:
>>> html_doc="""<html lang="en">
... <body>
... <div>ddd</div>
... bbooddyy
... <div>
... <p>pppp</p>
... </div>
... <input>
... <a></a>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> s.find_all("div")[1].string
>>> s.find_all("div")[1].text
'\npppp\n'
>>> s.find_all("div")[1].contents
['\n', <p>pppp</p>, '\n']
>>> s.find("div").contents="ascasdasdas"
>>> s.find("div").contents
'ascasdasdas'
##########################################################
<tag>.is_empty_element:判断是否为自闭合标签
#返回bool
#实例:
>>> html_doc="""<html lang="en">
... <body>
... <div>ddd</div>
... bbooddyy
... <div>
... <p>pppp</p>
... </div>
... <input>
... <a></a>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> s.find("input").is_empty_element
True
>>> s.find("a").is_empty_element
False
##########################################################
<pe>.next:相当于.next_element
<pe>.next_element:返回下1个节点
<pe>.next_elements:返回之后所有节点构成的生成器
<pe>.next_sibling:返回下1个兄弟节点
<pe>.next_siblings:返回之后所有兄弟节点构成的生成器
<pe>.previous:相当于.previous_element
<pe>.previous_element:返回上1个节点
<pe>.previous_elements:返回之前所有节点构成的生成器
<pe>.previous_sibling:返回上1个兄弟节点
<pe>.previous_siblings:返回之前所有兄弟节点构成的生成器
<pe>.parent:返回直接父节点
<pe>.parents:返回所有祖先节点构成的生成器
#.next/previous_element(s)功能中所说的之前/后指的是遍历时的顺序
#参数说明:
pe:为bs4.element.PageElement对象
#即表示页面的某部分的对象,如bs4.BeautifulSoup/bs4.element.Tag对象
#不过,对bs4.BeautifulSoup对象,以上各方法返回的都是None/空生成器
#实例:
>>> html_doc="""<html lang="en">
... <body>
... <div>ddd</div>
... bbooddyy
... <div>
... <p>pppp</p>
... </div>
... <input>
... <a></a>
... </body>
... </html>"""
>>> s=bs4.BeautifulSoup(html_doc)
>>> print(s.next_element)
None
>>> print(list(s.next_elements))
[]
>>> print(s.find_all("div")[1].next)
>>> print(s.find_all("div")[1].next.next)
<p>pppp</p>
>>> print(list(s.find("p").parents))
[<div>
<p>pppp</p>
</div>, <body>
<div>ddd</div>
bbooddyy
<div>
<p>pppp</p>
</div>
<input/>
<a></a>
</body>, <html lang="en">
<body>
<div>ddd</div>
bbooddyy
<div>
<p>pppp</p>
</div>
<input/>
<a></a>
</body>
</html>, <html lang="en">
<body>
<div>ddd</div>
bbooddyy
<div>
<p>pppp</p>
</div>
<input/>
<a></a>
</body>
</html>]
>>> print(s.find("div").next_sibling)
bbooddyy
>>> print(list(s.find("html").next_elements))
['\n', <body>
<div>ddd</div>
bbooddyy
<div>
<p>pppp</p>
</div>
<input/>
<a></a>
</body>, '\n', <div>ddd</div>, 'ddd', '\n bbooddyy\n ', <div>
<p>pppp</p>
</div>, '\n', <p>pppp</p>, 'pppp', '\n', '\n', <input/>, '\n', <a></a>, '\n', '\n']