章神的私房菜之資料預處理
阿新 • • 發佈:2022-05-03
安裝使用
# 安裝 pip3 install beautifulsoup4
from bs4 import BeautifulSoup
soup=BeautifulSoup(ret.text,'html.parser') # 傳資料
soup=BeautifulSaoup(open('a.html','r')) # 傳檔案
# html.parser內建解析器,速度稍微慢一些,但是不需要裝第三方模組
# lxml:速度快一些,但是需要安裝 pip3 install lxml
soup=BeautifulSoup(ret.text,'html.parser')
soup=BeautifulSoup(ret.text,'lxml')
# find(找到的第一個)
# find_all(找到的所有)
# 找頁面所有的li標籤
li_list=soup.find_all(name='li')
.text # 全部拿出來,拼在一起
.string # 只拿第一個
.strings # 全部拿出來生成一個迭代器
遍歷文件樹
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"id="id_p"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
soup=BeautifulSoup(html_doc,'lxml')
# 1.美化+自動補全閉合標籤
print(soup.prettify())
# 2.(通過.來查詢,只能找到第一個)
head=soup.head # Tag物件
title=head.title # Tag物件
# 3.獲取標籤的名稱
p=soup.body
print(p.name) # body #沒什麼卵用
# 4.獲取標籤的屬性
p=soup.p
# 獲取class屬性,可以有多個,所以拿到是列表
# 方式一
print(p['class']) # ['title']
print(p['id']) # id_p
# 方式二
print(p.get('class')) # ['title']
print(p.attrs['class']) # ['title']
# 5.獲取標籤內容
p=soup.p
print(p) # <p class="title" id="id_p"><b>The Dormouse's story</b></p>
print(p.text) # The Dormouse's story
print(p.string) # The Dormouse's story
# 6.巢狀選擇
title = soup.head.title.text # 獲取head下第一個title的內容
print(title) # The Dormouse's story
# 7.子節點、子孫節點
p1=soup.p.children # 迭代器
p2=soup.p.contents # 列表
print(p1) # <list_iterator object at 0x000001FA66E0C4A8>
print(list(p1)) # [<b>The Dormouse's story</b>]
print(p2) # [<b>The Dormouse's story</b>]
# 8.父節點、祖先節點
p1=soup.p.parent # 直接父節點
p2=soup.p.parents
print(p1)
# # print(len(list(p2)))
print(list(p2))
# 9.兄弟節點
print(soup.a.next_sibling) #下一個兄弟
print(soup.a.previous_sibling) #上一個兄弟
print(list(soup.a.next_siblings)) #下面的兄弟們=>生成器物件
print(soup.a.previous_siblings) #上面的兄弟們=>生成器物件
查詢文件樹
# 查詢文件樹(find,find_all),速度比遍歷文件樹慢
# 兩個配合著使用(soup.p.find())
# 五種過濾器: 字串、正則表示式、列表、True、方法
# 1.字串查詢 引號內是字串
p=soup.find(name='p') # <p class="title" id="id_p"><b>The Dormouse's story</b></p>
p=soup.find(name='body') # body標籤所以內容
print(p)
# 查詢類名是title的所有標籤,class是關鍵字,class_
ret=soup.find_all(class_='title') # [<p class="title" id="id_p"><b>The Dormouse's story</b></p>]
# 找id為xx的標籤
ret=soup.find_all(id='id_p') # [<p class="title" id="id_p"><b>The Dormouse's story</b></p>]
# href屬性為http://example.com/elsie的標籤
ret=soup.find_all(href='http://example.com/elsie') # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
# 2.正則表示式
import re
reg=re.compile('^id') # ^id開頭
ret=soup.find_all(id=reg) # 查詢以id開頭的id標籤
print(ret) # [<p class="title" id="id_p"><b>The Dormouse's story</b></p>]
# 3.列表
# or關係
ret=soup.find_all(id=['id_psafdsaf','link1']) # 查詢id有id_psafdsaf或者link1的標籤
ret=soup.find_all(class_=['title1','story']) # 查詢類名有title1或者story的標籤
# and關係
ret=soup.find_all(class_='title',name='p') # 查詢類名有title1並且name=p的標籤
# 4.true
# 所有有名字的標籤
ret=soup.find_all(name=True)
#所有有id的標籤
ret=soup.find_all(id=True)
# 所有有herf屬性的
ret=soup.find_all(href=True)
print(ret)
# 5.方法
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
print(soup.find_all(has_class_but_no_id))
# 6.其他使用
ret=soup.find_all(attrs={'class':"title"})
ret=soup.find_all(attrs={'id':"id_p1",'class':'title'})
print(ret)
# 7.limit(限制條數)
# soup.find() 就是find_all limit=1
ret=soup.find_all(name=True,limit=2)
print(len(ret)) # 2
# 8.recursive
# recursive=False (只找兒子)不遞迴查詢,只找第一層
ret=soup.body.find_all(name='p',recursive=False)
print(ret)
選擇器介紹
# bs4:自己的選擇器,css選擇器
# lxml:css選擇器,xpath選擇器
# selenium:自己的選擇器,css選擇器,xpath選擇器
# scrapy框架:自己的選擇器,css選擇器,xpath選擇器
# css選擇器,xpath選擇器會用了,它就是個通行證
CSS選擇器
# Tag物件.select("css選擇器")
from bs4 import BeautifulSoup
import requests
for i in range(1, 5):
i1 = str(i - 1)
i = str(i)
url = 'https://www.mzitu.com/202340/' + i
ret = requests.get(url,headers={'User-Agent': 'request', 'Referer': 'https://www.mzitu.com/206122/' + i1},proxies={'http': '47.115.54.89'}, )
soup = BeautifulSoup(ret.text, 'lxml')
案例:
# div>p:兒子 div p:子子孫孫
# 找div下最後一個a標籤 div a:last-child
print(soup.select('#list-1 li:nth-child(1)')[0].text) # 取第一個li標籤
print(soup.select('#list-1 li:nth-child(2)')[0].text) # 取第二個li標籤
print(soup.select('#list-1 li:nth-last-child(1)')[0].text) # 取倒數第一個li標籤
print(soup.select('#list-1 li:nth-last-child(2)')[0].text) # 取倒數第二個li標籤
print(soup.p.select('.sister')) # 可以組合使用。
print(soup.select('.sister span'))
print(soup.select('#link1'))
print(soup.select('#link1 span'))
print(soup.select('#list-2 .element.xxx'))
print(soup.select('#list-2')[0].select('.element')) #可以一直select,但其實沒必要,一條select就可以了
# 2、獲取屬性
print(soup.select('#list-2 h1')[0].attrs)
href = soup.select('body > div.main > div.content > div.main-image > p > a > img')
print(href[0].attrs['src']) # 圖片連結
# 3、獲取內容
# .get_text()
# .text
# .string
# .strings 變成迭代器
print(soup.select('#list-2 h1')[0].get_text())
xpath選擇器
# xpath選擇
# / 從根節點選取 /a 從根節點開始,往下找a標籤(子)
# //從匹配選擇的當前節點選擇文件中的節點,而不考慮它們的位置 //a 從根節點開始找a標籤(子子孫孫中所有a)
# . 選取當前節點。
# .. 選取當前節點的父節點。
# @ 選取屬性。
# 取值 /text()
# 取屬性 /@屬性名
使用:
from lxml import etree
html=etree.HTML(doc) # 傳字串
html=etree.parse('search.html',etree.HTMLParser()) # 傳檔案
# 1 文字獲取 標籤後加:/text() ********重點
a=html.xpath('//body//a[@href="image1.html"]/text()')
a=html.xpath('//body//a/text()')
# 2 屬性獲取 標籤後:/@href ********重點
a=html.xpath('//body//a/@href')
# 注意從1 開始取(不是從0)
a=html.xpath('//body//a[3]/@href')
# 3 所有節點
a=html.xpath('//*')
# 4 指定節點(結果為列表)
a=html.xpath('//head')
# 5 子節點,子孫節點
a=html.xpath('//div/a')
a=html.xpath('//body/a') #無資料
a=html.xpath('//body//a')
# 6 父節點
a=html.xpath('//body//a[@href="image1.html"]/..')
a=html.xpath('//body//a[@href="image1.html"]')
a=html.xpath('//body//a[1]/..')
也可以這樣
a=html.xpath('//body//a[1]/parent::*')
# 7 屬性匹配
a=html.xpath('//body//a[@href="image1.html"]')
# 8 屬性多值匹配
a 標籤有多個class類,直接匹配就不可以了,需要用contains
a=html.xpath('//body//a[@class="li"]')
a=html.xpath('//body//a[@href="image1.html"]')
a=html.xpath('//body//a[contains(@class,"li")]')
a=html.xpath('//body//a[contains(@class,"li")]/text()')
a=html.xpath('//body//a[contains(@class,"li")]/@name')
# 9 多屬性匹配 or 和 and (瞭解)
a=html.xpath('//body//a[contains(@class,"li") or @name="items"]')
a=html.xpath('//body//a[contains(@class,"li") and @name="items"]/text()')
a=html.xpath('//body//a[contains(@class,"li")]/text()')
# 10 按序選擇
a=html.xpath('//a[2]/text()')
a=html.xpath('//a[2]/@href')
# 取最後一個(瞭解)
a=html.xpath('//a[last()]/@href')
a=html.xpath('//a[last()]/text()')
# 位置小於3的
a=html.xpath('//a[position()<3]/@href')
a=html.xpath('//a[position()<3]/text()')
# 倒數第二個
a=html.xpath('//a[last()-2]/@href')
# 11 節點軸選擇
ancestor:祖先節點
使用了* 獲取所有祖先節點
a=html.xpath('//a/ancestor::*')
# # 獲取祖先節點中的div
a=html.xpath('//a/ancestor::div')
a=html.xpath('//a/ancestor::div/a[2]/text()')
# attribute:屬性值
a=html.xpath('//a[1]/attribute::*')
a=html.xpath('//a[1]/@href')
# child:直接子節點
a=html.xpath('//a[1]/child::*')
a=html.xpath('//a[1]/img/@src')
descendant:所有子孫節點
a=html.xpath('//a[6]/descendant::*')
following:當前節點之後所有節點(遞迴)
a=html.xpath('//a[1]/following::*')
a=html.xpath('//a[1]/following::*[1]/@href')
# following-sibling:當前節點之後同級節點(同級)
a=html.xpath('//a[1]/following-sibling::*')
a=html.xpath('//a[1]/following-sibling::a')
a=html.xpath('//a[1]/following-sibling::*[2]')
a=html.xpath('//a[1]/following-sibling::*[2]/@href')