一,正則表達式解析
re正則就不寫了,前面已經寫入一篇很詳細的正則表達式模塊了~
而且,在爬蟲中,下面兩種方式用的多一些~
正則表達式:https://www.cnblogs.com/peng104/p/9619801.html
大致用法:
pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?src="(.*?)".*?name"><a' +'.*?>(.*?)</a>.*?star">(.*?)</p>.*?releasetime">(.*?)</p>' +'.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S) items = re.findall(pattern, html)
二,Xpath解析
簡介及安裝
簡介:XPath 是一門在 XML 文檔中查找信息的語言。XPath 可用來在 XML 文檔中對元素和屬性進行遍歷。XPath 是 W3C XSLT 標准的主要元素,並且 XQuery 和 XPointer 都構建於 XPath 表達之上。
安裝:pip install lxml
調用方法:
# 先導包 from lxml import etree # 將html文檔或者xml文檔轉換成一個etree對象,然后調用對象中的方法查找指定的節點 # 1. 本地文件 tree = etree.parse(文件名) tree.xpath("xpath表達式") # 2. 網絡數據 tree = etree.HTML(網頁內容字符串) tree.xpath("xpath表達式")
語法簡介
先准備一個HTML格式的字符串

html_doc = """ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div class="d1"> <div class="d2"> <p class="story"> <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" id="link3">Tillie</a> </p> </div> <div> <p id="p1">人生苦短</p> <p id="p2">我用python</p> </div> </div> <div class="d3"> <a href="http://www.baidu.com">baidu</a> <p>百度</p> </div> </body> </html> """
1,選取節點
nodename # 選取nodename節點的所有子節點 xpath(‘//div’) # 選取了所有div節點 / # 從根節點選取 xpath(‘/div’) # 從根節點上選取div節點 // # 選取所有的當前節點,不考慮他們的位置 xpath(‘//div’) # 選取所有的div節點 . # 選取當前節點 xpath(‘./div’) # 選取當前節點下的div節點 .. # 選取當前節點的父節點 xpath(‘..’) # 回到上一個節點 @ # 選取屬性 xpath(’//@calss’) # 選取所有的class屬性 #######################⬇例子⬇###################### ret=selector.xpath("//div") ret=selector.xpath("/div") ret=selector.xpath("./div") ret=selector.xpath("//p[@id='p1']") ret=selector.xpath("//div[@class='d1']/div/p[@class='story']")
2,謂語
表達式 結果 xpath(‘/body/div[1]’) # 選取body下的第一個div節點 xpath(‘/body/div[last()]’) # 選取body下最后一個div節點 xpath(‘/body/div[last()-1]’) # 選取body下倒數第二個div節點 xpath(‘/body/div[positon()<3]’) # 選取body下前兩個div節點 xpath(‘/body/div[@class]’) # 選取body下帶有class屬性的div節點 xpath(‘/body/div[@class=”main”]’) # 選取body下class屬性為main的div節點 xpath(‘/body/div[@price>35.00]’) # 選取body下price元素值大於35的div節點 #######################⬇例子⬇###################### ret=selector.xpath("//p[@class='story']//a[2]") ret=selector.xpath("//p[@class='story']//a[last()]")
3,通配符
Xpath通過通配符來選取未知的XML元素
表達式 結果 xpath(’/div/*’) # 選取div下的所有子節點 xpath(‘/div[@*]’) # 選取所有帶屬性的div節點 #######################⬇例子⬇###################### ret=selector.xpath("//p[@class='story']/*") ret=selector.xpath("//p[@class='story']/a[@class]")
4,取多個路徑
使用 “|” 運算符可以選取多個路徑
表達式 結果 xpath(‘//div|//table’) # 選取所有的div和table節點 #######################⬇例子⬇###################### ret=selector.xpath("//p[@class='story']/a[@class]|//div[@class='d3']") print(ret)
5,Xpath軸
軸可以定義相對於當前節點的節點集
軸名稱 表達式 描述 ancestor xpath(‘./ancestor::*’) # 選取當前節點的所有先輩節點(父、祖父) ancestor-or-self xpath(‘./ancestor-or-self::*’) # 選取當前節點的所有先輩節點以及節點本身 attribute xpath(‘./attribute::*’) # 選取當前節點的所有屬性 child xpath(‘./child::*’) # 返回當前節點的所有子節點 descendant xpath(‘./descendant::*’) # 返回當前節點的所有后代節點(子節點、孫節點) following xpath(‘./following::*’) # 選取文檔中當前節點結束標簽后的所有節點 following-sibing xpath(‘./following-sibing::*’) # 選取當前節點之后的兄弟節點 parent xpath(‘./parent::*’) # 選取當前節點的父節點 preceding xpath(‘./preceding::*’) # 選取文檔中當前節點開始標簽前的所有節點 preceding-sibling xpath(‘./preceding-sibling::*’) # 選取當前節點之前的兄弟節點 self xpath(‘./self::*’) # 選取當前節點
6,功能函數
使用功能函數能夠更好的進行模糊搜索
函數 用法 解釋 starts-with xpath(‘//div[starts-with(@id,”ma”)]‘) # 選取id值以ma開頭的div節點 contains xpath(‘//div[contains(@id,”ma”)]‘) # 選取id值包含ma的div節點 and xpath(‘//div[contains(@id,”ma”) and contains(@id,”in”)]‘) # 選取id值包含ma和in的div節點 text() xpath(‘//div[contains(text(),”ma”)]‘) # 選取節點文本包含ma的div節點
Element對象
from lxml.etree import _Element for obj in ret: print(obj) print(type(obj)) # from lxml.etree import _Element ''' Element對象 class xml.etree.ElementTree.Element(tag, attrib={}, **extra) tag:string,元素代表的數據種類。 text:string,元素的內容。 tail:string,元素的尾形。 attrib:dictionary,元素的屬性字典。 #針對屬性的操作 clear():清空元素的后代、屬性、text和tail也設置為None。 get(key, default=None):獲取key對應的屬性值,如該屬性不存在則返回default值。 items():根據屬性字典返回一個列表,列表元素為(key, value)。 keys():返回包含所有元素屬性鍵的列表。 set(key, value):設置新的屬性鍵與值。 #針對后代的操作 append(subelement):添加直系子元素。 extend(subelements):增加一串元素對象作為子元素。#python2.7新特性 find(match):尋找第一個匹配子元素,匹配對象可以為tag或path。 findall(match):尋找所有匹配子元素,匹配對象可以為tag或path。 findtext(match):尋找第一個匹配子元素,返回其text值。匹配對象可以為tag或path。 insert(index, element):在指定位置插入子元素。 iter(tag=None):生成遍歷當前元素所有后代或者給定tag的后代的迭代器。#python2.7新特性 iterfind(match):根據tag或path查找所有的后代。 itertext():遍歷所有后代並返回text值。 remove(subelement):刪除子元素。 '''
三,BeautifulSoup
簡介及安裝
簡介:
Beautiful Soup提供一些簡單的、python式的函數用來處理導航、搜索、修改分析樹等功能。
它是一個工具箱,通過解析文檔為用戶提供需要抓取的數據,因為簡單,所以不需要多少代碼就可以寫出一個完整的應用程序。
安裝:pip3 install beautifulsoup4
解析器:
Beautiful Soup支持Python標准庫中的HTML解析器,還支持一些第三方的解析器,如果我們不安裝它,則 Python 會使用 Python默認的解析器,lxml 解析器更加強大,速度更快。
簡單使用
使用方式:可以將一個html文檔,轉化為BeautifulSoup對象,然后通過對象的方法或者屬性去查找指定的節點內容
from bs4 import BeautifulSoup # 轉化本地文件 soup = BeautifulSoup(open('本地文件'), 'lxml') # 轉化網絡文件 soup = BeautifulSoup('字符串類型或者字節類型', 'lxml') # 從文檔中獲取所有文字內容: print(soup.get_text())
語法簡介
# 1.根據標簽名查找 - soup.a 只能找到第一個符合要求的標簽 # 2.獲取屬性 - soup.a.attrs 獲取a所有的屬性和屬性值,返回一個字典 - soup.a.attrs['href'] 獲取href屬性 - soup.a['href'] 也可簡寫為這種形式 # 3.獲取內容 - soup.a.string - soup.a.text - soup.a.get_text() 注意:如果標簽還有標簽,那么string獲取到的結果為None,而其它兩個,可以獲取文本內容 # 4.find:找到第一個符合要求的標簽 - soup.find('a') 找到第一個符合要求的 - soup.find('a', title="xxx") - soup.find('a', alt="xxx") - soup.find('a', class_="xxx") - soup.find('a', id="xxx") # 5.find_all:找到所有符合要求的標簽 - soup.find_all('a') - soup.find_all(['a','b']) 找到所有的a和b標簽 - soup.find_all('a', limit=2) 限制前兩個 # 6.根據選擇器選擇指定的內容 select:soup.select('#feng') - 常見的選擇器:標簽選擇器(a)、類選擇器(.)、id選擇器(#)、層級選擇器 - 層級選擇器: div .dudu #lala .meme .xixi 下面好多級 div > p > a > .lala 只能是下面一級 注意:select選擇器返回永遠是列表,需要通過下標提取指定的對象
find_all()
先准備一個HTML格式的字符串

html_doc = """ <html><head><title>The Dormouse's story</title></head> <body> <p id="my p" class="title"><b id="bbb" class="boldest">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> """
1,五種過濾器
字符串、正則表達式、列表、True、方法
from bs4 import BeautifulSoup soup=BeautifulSoup(html_doc,'lxml') #1、字符串:即標簽名 print(soup.find_all('b')) #2、正則表達式 import re print(soup.find_all(re.compile('^b'))) #找出b開頭的標簽,結果有body和b標簽 #3、列表:如果傳入列表參數,Beautiful Soup會將與列表中任一元素匹配的內容返回.下面代碼找到文檔中所有<a>標簽和<b>標簽: print(soup.find_all(['a','b'])) #4、True:可以匹配任何值,下面代碼查找到所有的tag,但是不會返回字符串節點 print(soup.find_all(True)) for tag in soup.find_all(True): print(tag.name) #5、方法:如果沒有合適過濾器,那么還可以定義一個方法,方法只接受一個元素參數 ,如果這個方法返回 True 表示當前元素匹配並且被找到,如果不是則反回 False 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))
2、按照類名查找
注意:關鍵字是class_,class_=value,value可以是五種選擇器之一
print(soup.find_all('a',class_='sister')) # 查找類為sister的a標簽 print(soup.find_all('a',class_='sister ssss')) # 查找類為sister和sss的a標簽,順序錯誤也匹配不成功 print(soup.find_all(class_=re.compile('^sis'))) # 查找類為sister的所有標簽
3、attrs
print(soup.find_all('p',attrs={'class':'story'}))
4、text
值可以是:字符,列表,True,正則
print(soup.find_all(text='Elsie')) print(soup.find_all('a',text='Elsie'))
5、limit參數
如果文檔樹很大那么搜索會很慢.如果我們不需要全部結果,可以使用 limit 參數限制返回結果的數量.效果與SQL中的limit關鍵字類似,當搜索到的結果數量達到 limit 的限制時,就停止搜索返回結果
print(soup.find_all('a',limit=2))
6、recursive
調用tag的 find_all() 方法時,Beautiful Soup會檢索當前tag的所有子孫節點,如果只想搜索tag的直接子節點,可以使用參數 recursive=False .
print(soup.html.find_all('a')) print(soup.html.find_all('a',recursive=False))
tag
像調用 find_all() 一樣調用tag find_all() 幾乎是Beautiful Soup中最常用的搜索方法,所以我們定義了它的簡寫方法. BeautifulSoup 對象和 tag 對象可以被當作一個方法來使用~
這個方法的執行結果與調用這個對象的 find_all() 方法相同~
# 下面兩行代碼是等價的: soup.find_all("a") soup("a") # 這兩行代碼也是等價的: soup.title.find_all(text=True) soup.title(text=True)
find
find( name , attrs , recursive , text , **kwargs )
find_all() 方法將返回文檔中符合條件的所有tag,盡管有時候我們只想得到一個結果.比如文檔中只有一個<body>標簽,那么使用 find_all() 方法來查找<body>標簽就不太合適, 使用 find_all 方法並設置 limit=1 參數不如直接使用 find() 方法
下面兩行代碼是等價的: soup.find_all('title', limit=1) # [<title>The Dormouse's story</title>] soup.find('title') # <title>The Dormouse's story</title>
唯一的區別是 find_all() 方法的返回結果是值包含一個元素的列表,而 find() 方法直接返回結果.
find_all() 方法沒有找到目標是返回空列表, find() 方法找不到目標時,返回 None .
print(soup.find("nosuchtag")) # None
soup.head.title 是 tag的名字 方法的簡寫.這個簡寫的原理就是多次調用當前tag的 find() 方法:
soup.head.title # <title>The Dormouse's story</title> soup.find("head").find("title") # <title>The Dormouse's story</title>