学习beautifulsoup基础知识。
使用beautifulsoup解析HTML页面。
第一步:pip install beautifulsoup4 ,万事开头难,先安装 beautifulsoup4,安装成功后就完成了第一步。
第二步:导入from bs4 import BeautifulSoup
第三步:创建 Beautiful Soup对象 soup = BeautifulSoup(html,‘html.parser’)
Beautiful Soup库的理解:
Beautiful Soup库是解析、遍历、维护“标签树”的功能库,对应一个HTML/XML文档的全部内容
BeautifulSoup类的基本元素:
Tag 标签,最基本的信息组织单元,分别用<>和>标明开头和结尾;
Name 标签的名字,…
的名字是'p',格式:.name;
Attributes 标签的属性,字典形式组织,格式:.attrs;
NavigableString 标签内非属性字符串,<>…>中字符串,格式:.string;
Comment 标签内字符串的注释部分,一种特殊的Comment类型;
序号 | 解析库 | 使用方法 | 优势 | 劣势 |
---|---|---|---|---|
1 | Python标准库 | BeautifulSoup(html,’html.parser’) | Python内置标准库;执行速度快 | 容错能力较差 |
2 | lxml HTML解析库 | BeautifulSoup(html,’lxml’) | 速度快;容错能力强;支持XML格式 | 需要安装,需要C语言库 |
3 | lxml XML解析库 | BeautifulSoup(html,[‘lxml’,’xml’]) | 速度快;容错能力强; | 需要C语言库 |
4 | htm5lib解析库 | BeautifulSoup(html,’htm5llib’) | 以浏览器方式解析,最好的容错性 | 速度慢 |
# 导入bs4库
from bs4 import BeautifulSoup
import requests # 抓取页面
r = requests.get('https://python123.io/ws/demo.html') # Demo网址
demo = r.text # 抓取的数据
demo
'This is a python demo page \r\n\r\nThe demo python introduces several python courses.
\r\nPython is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\nBasic Python and Advanced Python.
\r\n'
# 解析HTML页面
soup = BeautifulSoup(demo, 'lxml') # 抓取的页面数据;bs4的解析器
# 有层次感的输出解析后的HTML页面
print(soup.prettify())
This is a python demo page
The demo python introduces several python courses.
Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
Basic Python
and
Advanced Python
.
1)标签,用soup.访问获得:
当HTML文档中存在多个相同对应内容时,soup.返回第一个
soup.a # 访问标签a
Basic Python
soup.title
This is a python demo page
soup.a.next_sibling.next_sibling #兄弟结点
Advanced Python
2)标签的名字:每个都有自己的名字,通过soup..name获取,字符串类型
soup.a.name
'a'
soup.a.parent.name
'p'
soup.p.parent.name
'body'
3)标签的属性,一个可以有0或多个属性,字典类型,soup..attrs
tag = soup.a
print(tag.attrs)
print(tag.attrs['class'])
print(type(tag.attrs))
{'href': 'http://www.icourse163.org/course/BIT-268001', 'class': ['py1'], 'id': 'link1'}
['py1']
4)Attributes:标签内非属性字符串,格式:soup..string, NavigableString可以跨越多个层次
print(soup.a.string)
print(type(soup.a.string))
Basic Python
5)NavigableString:标签内字符串的注释部分,Comment是一种特殊类型(有-->)
print(type(soup.p.string))
.prettify()print(soup.prettify())
This is a python demo page
The demo python introduces several python courses.
Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
Basic Python
and
Advanced Python
.
print(soup.a.prettify())
Basic Python
newsoup = BeautifulSoup('中文', 'html.parser')
print(newsoup.prettify())
中文
HTML基本格式:<>…>
构成了所属关系,形成了标签的树形结构
所有儿子节点存入列表import requests
from bs4 import BeautifulSoup
r=requests.get('http://python123.io/ws/demo.html')
demo=r.text
soup=BeautifulSoup(demo,'html.parser')
print(soup.contents)# 获取整个标签树的儿子节点
[This is a python demo page
The demo python introduces several python courses.
Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
Basic Python and Advanced Python.
]
print(soup.body.contents)#返回标签树的body标签下的节点
['\n', The demo python introduces several python courses.
, '\n', Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
Basic Python and Advanced Python.
, '\n']
print(soup.head)#返回head标签
This is a python demo page
for child in soup.body.children:#遍历儿子节点
print(child)
The demo python introduces several python courses.
Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
Basic Python and Advanced Python.
for child in soup.body.descendants:#遍历子孙节点
print(child)
The demo python introduces several python courses.
The demo python introduces several python courses.
The demo python introduces several python courses.
Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
Basic Python and Advanced Python.
Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
Basic Python
Basic Python
and
Advanced Python
Advanced Python
.
soup.title.parent
This is a python demo page
soup.title.parent.parent
This is a python demo page
The demo python introduces several python courses.
Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
Basic Python and Advanced Python.
soup.parent
for parent in soup.a.parents: # 遍历先辈的信息
if parent is None:
print(parent)
else:
print(parent.name)
p
body
html
[document]
注意:
print(soup.a.next_sibling)#a标签的下一个标签
and
print(soup.a.next_sibling.next_sibling)#a标签的下一个标签的下一个标签
Advanced Python
print(soup.a.previous_sibling)#a标签的前一个标签
Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
print(soup.a.previous_sibling.previous_sibling)#a标签的前一个标签的前一个标签
None
for sibling in soup.a.next_siblings:#遍历后续节点
print(sibling)
and
Advanced Python
.
for sibling in soup.a.previous_sibling:#遍历之前的节点
#print(sibling)
pass
(…) 等价于
.find_all(…)import requests
from bs4 import BeautifulSoup
r = requests.get('http://python123.io/ws/demo.html')
demo = r.text
soup = BeautifulSoup(demo,'html.parser')
# name : 对标签名称的检索字符串
soup.find_all('a')
[Basic Python,
Advanced Python]
soup.find_all(['a', 'p'])
[The demo python introduces several python courses.
,
Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
Basic Python and Advanced Python.
,
Basic Python,
Advanced Python]
# attrs: 对标签属性值的检索字符串,可标注属性检索
soup.find_all("p","course")
[Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
Basic Python and Advanced Python.
]
soup.find_all(id="link1") # 完全匹配才能匹配到
[Basic Python]
soup.find_all(id="link") # 完全匹配才能匹配到
[]
# recursive: 是否对子孙全部检索,默认True
soup.find_all('p',recursive=False)
[]
# string: <>…>中字符串区域的检索字符串
soup.find_all(string = "Basic Python") # 完全匹配才能匹配到
['Basic Python']
# 导入库
import pandas as pd
import requests
from bs4 import BeautifulSoup
import bs4
url = 'http://www.zuihaodaxue.cn/zuihaodaxuepaiming2019.html'
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"}
res = requests.get(url, headers=headers)
res.encoding = 'utf-8'
text = res.text
soup = BeautifulSoup(text, 'html.parser')
data = {
'排名' : [], '学校' : [], '省市' : [], '总分' : [], '指标(生源质量)' : []}
soup = BeautifulSoup(text, 'html.parser')
for i in soup.find_all("tr")[1:]:
i = i.td
data['排名'].append(i.contents[0])
i = i.next_sibling
data['学校'].append(i.div.contents[0])
i = i.next_sibling
data['省市'].append(i.contents[0])
i = i.next_sibling
data['总分'].append(i.contents[0])
i = i.next_sibling
data['指标(生源质量)'].append(i.contents[0])
res = pd.DataFrame(data)
res.to_csv('rank_school.csv', index=0, encoding='utf_8_sig')
res.head()
排名 | 学校 | 省市 | 总分 | 指标(生源质量) | |
---|---|---|---|---|---|
0 | 1 | 清华大学 | 北京 | 94.6 | 100.0 |
1 | 2 | 北京大学 | 北京 | 76.5 | 95.2 |
2 | 3 | 浙江大学 | 浙江 | 72.9 | 84.2 |
3 | 4 | 上海交通大学 | 上海 | 72.1 | 91.1 |
4 | 5 | 复旦大学 | 上海 | 65.6 | 91.6 |
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。
在XPath中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。
XML文档是被作为节点树来对待的。
XPath使用路径表达式在XML文档中选取节点。节点是通过沿着路径选取的。下面列出了最常用的路径表达式:
nodename 选取此节点的所有子节点。
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
… 选取当前节点的父节点。
@ 选取属性。
/text() 提取标签下面的文本内容
详细学习:https://www.cnblogs.com/gaojun/archive/2012/08/11/2633908.html
导入库:from lxml import etree
lxml将html文本转成xml对象
用户名称:tree.xpath(’//div[@class=“auth”]/a/text()’)
回复内容:tree.xpath(’//td[@class=“postbody”]’) 因为回复内容中有换行等标签,所以需要用string()来获取数据。
Xpath中text(),string(),data()的区别如下:
# 导入库
from lxml import etree
import requests
url = "http://www.dxy.cn/bbs/thread/626626#626626"
req = requests.get(url)
html = req.text
# html
tree = etree.HTML(html)
tree
user = tree.xpath('//div[@class="auth"]/a/text()')
print(user)
content = tree.xpath('//td[@class="postbody"]')
print(content)
['楼医生', 'lion000', 'xghrh', 'keys']
[, , , ]
results = []
for i in range(0, len(user)):
print(user[i].strip()+":"+content[i].xpath('string(.)').strip())
# print("*"*80)
# 因为回复内容中有换行等标签,所以需要用string()来获取数据
results.append(user[i].strip() + ": " + content[i].xpath('string(.)').strip())
楼医生:我遇到一个“怪”病人,向大家请教。她,42岁。反复惊吓后晕厥30余年。每次受响声惊吓后发生跌倒,短暂意识丧失。无逆行性遗忘,无抽搐,无口吐白沫,无大小便失禁。多次跌倒致外伤。婴儿时有惊厥史。入院查体无殊。ECG、24小时动态心电图无殊;头颅MRI示小软化灶;脑电图无殊。入院后有数次类似发作。请问该患者该做何诊断,还需做什么检查,治疗方案怎样?
lion000:从发作的症状上比较符合血管迷走神经性晕厥,直立倾斜试验能协助诊断。在行直立倾斜实验前应该做常规的体格检查、ECG、UCG、holter和X-ray胸片除外器质性心脏病。贴一篇“口服氨酰心安和依那普利治疗血管迷走性晕厥的疗效观察”作者:林文华 任自文 丁燕生http://www.ccheart.com.cn/ccheart_site/Templates/jieru/200011/1-1.htm
xghrh:同意lion000版主的观点:如果此患者随着年龄的增长,其发作频率逐渐减少且更加支持,不知此患者有无这一特点。入院后的HOLTER及血压监测对此患者只能是一种安慰性的检查,因在这些检查过程中患者发病的机会不是太大,当然不排除正好发作的情况。对此患者应常规作直立倾斜试验,如果没有诱发出,再考虑有无可能是其他原因所致的意识障碍,如室性心动过速等,但这需要电生理尤其是心腔内电生理的检查,毕竟是有一种创伤性方法。因在外地,下面一篇文章可能对您有助,请您自己查找一下。心理应激事件诱发血管迷走性晕厥1例 ,杨峻青、吴沃栋、张瑞云,中国神经精神疾病杂志, 2002 Vol.28 No.2
keys:该例不排除精神因素导致的,因为每次均在受惊吓后出现。当然,在作出此诊断前,应完善相关检查,如头颅MIR(MRA),直立倾斜试验等。
# 打印爬取的结果
for i,result in zip(range(0, len(user)),results):
print("user"+ str(i+1) + "-" + result)
print("*"*100)
user1-楼医生: 我遇到一个“怪”病人,向大家请教。她,42岁。反复惊吓后晕厥30余年。每次受响声惊吓后发生跌倒,短暂意识丧失。无逆行性遗忘,无抽搐,无口吐白沫,无大小便失禁。多次跌倒致外伤。婴儿时有惊厥史。入院查体无殊。ECG、24小时动态心电图无殊;头颅MRI示小软化灶;脑电图无殊。入院后有数次类似发作。请问该患者该做何诊断,还需做什么检查,治疗方案怎样?
****************************************************************************************************
user2-lion000: 从发作的症状上比较符合血管迷走神经性晕厥,直立倾斜试验能协助诊断。在行直立倾斜实验前应该做常规的体格检查、ECG、UCG、holter和X-ray胸片除外器质性心脏病。贴一篇“口服氨酰心安和依那普利治疗血管迷走性晕厥的疗效观察”作者:林文华 任自文 丁燕生http://www.ccheart.com.cn/ccheart_site/Templates/jieru/200011/1-1.htm
****************************************************************************************************
user3-xghrh: 同意lion000版主的观点:如果此患者随着年龄的增长,其发作频率逐渐减少且更加支持,不知此患者有无这一特点。入院后的HOLTER及血压监测对此患者只能是一种安慰性的检查,因在这些检查过程中患者发病的机会不是太大,当然不排除正好发作的情况。对此患者应常规作直立倾斜试验,如果没有诱发出,再考虑有无可能是其他原因所致的意识障碍,如室性心动过速等,但这需要电生理尤其是心腔内电生理的检查,毕竟是有一种创伤性方法。因在外地,下面一篇文章可能对您有助,请您自己查找一下。心理应激事件诱发血管迷走性晕厥1例 ,杨峻青、吴沃栋、张瑞云,中国神经精神疾病杂志, 2002 Vol.28 No.2
****************************************************************************************************
user4-keys: 该例不排除精神因素导致的,因为每次均在受惊吓后出现。当然,在作出此诊断前,应完善相关检查,如头颅MIR(MRA),直立倾斜试验等。
****************************************************************************************************
典型的搜索和替换操作要求您提供与预期的搜索结果匹配的确切文本。虽然这种技术对于对静态文本执行简单搜索和替换任务可能已经足够了,但它缺乏灵活性,若采用这种方法搜索动态文本,即使不是不可能,至少也会变得很困难。
通过使用正则表达式,可以:
- 测试字符串内的模式。
例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。
- 替换文本。
可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
- 基于模式匹配从字符串中提取子字符串。
可以查找文档内或输入域内特定的文本。
可以使用正则表达式来搜索和替换标记。
正则表达式语法由字符和操作符构成:
.
表示任何单个字符
[ ]
字符集,对单个字符给出取值范围 ,如[abc]
表示a、b、c,[a‐z]
表示a到z单个字符
[^ ]
非字符集,对单个字符给出排除范围 ,如[^abc]
表示非a或b或c的单个字符
*
前一个字符0次或无限次扩展,如abc* 表示 ab、abc、abcc、abccc等
+
前一个字符1次或无限次扩展 ,如abc+ 表示 abc、abcc、abccc等
?
前一个字符0次或1次扩展 ,如abc? 表示 ab、abc
|
左右表达式任意一个 ,如abc|def 表示 abc、def
{m}
扩展前一个字符m次 ,如ab{2}c表示abbc
{m,n}
扩展前一个字符m至n次(含n) ,如ab{1,2}c表示abc、abbc
^
匹配字符串开头 ,如^abc表示abc且在一个字符串的开头
$
匹配字符串结尾 ,如abc$表示abc且在一个字符串的结尾
( )
分组标记,内部只能使用 | 操作符 ,如(abc)表示abc,(abc|def)表示abc、def
\d
数字,等价于[0‐9]
\w
单词字符,等价于[A‐Za‐z0‐9_]
re.sub(pattern, repl, string, count=0, flags=0)
flags : 正则表达式使用时的控制标记:
[A‐Z]
能够匹配小写字符.*
Re库默认采用贪婪匹配,即输出匹配最长的子串*?
只要长度输出可能不同的,都可以通过在操作符后增加?变成最小匹配# 导入包
import requests
import re
def getHTMLText(url):
"""
请求获取html,(字符串)
:param url: 爬取网址
:return: 字符串
"""
try:
# 添加头信息,
kv = {
'cookie': 'cna=FQ6bFUy7VysCAcrO0Z/oOegQ; thw=cn; _samesite_flag_=true; cookie2=191b29a86a432b0492bb74fa22bb3862; t=d9dabb64e2c99e4b141c6fc76f7f8dba; _tb_token_=e36ede550e830; sgcookie=EIq805RvnotbZAssy%2FVSx; unb=2961883452; uc3=nk2=GgW6V27uSw%3D%3D&id2=UUGk3%2FwLdp%2FKmw%3D%3D&vt3=F8dBxGR1SdDTfSo20fg%3D&lg2=WqG3DMC9VAQiUQ%3D%3D; csg=fd34e7d8; lgc=yndlcxd; cookie17=UUGk3%2FwLdp%2FKmw%3D%3D; dnk=yndlcxd; skt=f311dec7dddc96e8; existShop=MTU4NzYxMzA3Nw%3D%3D; uc4=nk4=0%40GIn%2FUxQvM8FFHSUQeJ5vKc4%2B&id4=0%40U2OT74%2FMK7XZjHgM9nG1pYpLjyUe; tracknick=yndlcxd; _cc_=Vq8l%2BKCLiw%3D%3D; _l_g_=Ug%3D%3D; sg=d25; _nk_=yndlcxd; cookie1=WqUOz2JF7OhGqXmqRNgJoTDwXuhJfvZEObuBXJQ5OeA%3D; enc=hOUab%2BC%2F07zBT5Eh9WHW5JJy6CSOkJ9yvS6rwJ14cYtQ13vouWed%2F3UgK1hzpLg9v3bv%2BJ%2BWaqjcVhqO89CqBg%3D%3D; tfstk=cimABJNFPQA0blM48cLufMUPIg9hZwWYstNOXd1b9s8eqjsOidonv2aHlR5Y2LC..; mt=ci=14_1; v=0; hng=CN%7Czh-CN%7CCNY%7C156; alitrackid=localhost; lastalitrackid=localhost; uc1=cookie14=UoTUPcqd8L0gxg%3D%3D&cookie16=WqG3DMC9UpAPBHGz5QBErFxlCA%3D%3D&existShop=false&cookie21=U%2BGCWk%2F7pY%2FF&cookie15=URm48syIIVrSKA%3D%3D&pas=0; JSESSIONID=ACEAA02C4025BC4D86311F2A2F986864; isg=BBMTRDaKSZtfVAUft1MKSBH1opc9yKeKx0MPPcUxIDJpRDLmTZxV2jXWfrQqZP-C; l=eBOdkAbrQyzfiR7sBO5iRK9hRpbOqIOb8sPPl_fm3IHca61ctFg15NQccM2WSdtjgtfEXetyIQLleRHBPizdg2HvCbKrCyCkDY96-',
'user-agent': 'Mozilla/5.0'
}
r = requests.get(url, timeout=30, headers=kv)
# r = requests.get(url, timeout=30)
# print(r.status_code)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return "爬取失败"
def parsePage(glist, html):
'''
解析网页,搜索需要的信息
:param glist: 列表作为存储容器
:param html: 由getHTMLText()得到的
:return: 商品信息的列表
'''
try:
# 使用正则表达式提取信息
#商品价格
price_list = re.findall(r'\"view_price\"\:\"[\d\.]*\"', html)
#商品名称
name_list = re.findall(r'\"raw_title\"\:\".*?\"', html)
for i in range(len(price_list)):
price = eval(price_list[i].split(":")[1]) #eval()在此可以去掉""
name = eval(name_list[i].split(":")[1])
glist.append([price, name])
except:
print("解析失败")
def printGoodList(glist):
tplt = "{0:^4}\t{1:^6}\t{2:^10}"
print(tplt.format("序号", "商品价格", "商品名称"))
count = 0
for g in glist:
count = count + 1
print(tplt.format(count, g[0], g[1]))
# 根据页面url的变化寻找规律,构建爬取url
goods_name = "书包" # 搜索商品类型
start_url = "https://s.taobao.com/search?q=" + goods_name
info_list = []
page = 3 # 爬取页面数量
count = 0
for i in range(page):
count += 1
try:
url = start_url + "&s=" + str(44 * i)
html = getHTMLText(url) # 爬取url
parsePage(info_list, html) #解析HTML和爬取内容
print("\r爬取页面当前进度: {:.2f}%".format(count * 100 / page), end="") # 显示进度条
except:
continue
爬取页面当前进度: 100.00%
#printGoodList(info_list)