爬蟲處理之結(jié)構(gòu)化數(shù)據(jù)操作
目錄清單
1.正則表達(dá)式提取數(shù)據(jù)
2.正則表達(dá)式案例操作
1.Xpath提取數(shù)據(jù)
Xpath案例操作
BeautifulSoup4提取數(shù)據(jù)
BeautifulSoup4案例操作
章節(jié)內(nèi)容
1.關(guān)于數(shù)據(jù)
爬蟲程序,主要是運(yùn)行在網(wǎng)絡(luò)中進(jìn)行數(shù)據(jù)采集的一種計(jì)算機(jī)程序,正常的一個(gè)爬蟲采集數(shù)據(jù)的過程大致如下:
訪問目標(biāo)服務(wù)器
采集數(shù)據(jù)瞬项,獲取訪問url的數(shù)據(jù)
根據(jù)需要篩選數(shù)據(jù)
處理數(shù)據(jù),存儲到文件或者數(shù)據(jù)庫汇陆,等待下一步進(jìn)行數(shù)據(jù)分析或者數(shù)據(jù)展示
由于存在著不同的服務(wù)器和軟件應(yīng)用北秽,所以爬蟲獲取到的數(shù)據(jù)就會出現(xiàn)各種不同的表現(xiàn)形式,但是總體來說還是有規(guī)律的呢铆,有規(guī)律就可以被掌握的
首先贷屎,關(guān)于爬蟲處理的數(shù)據(jù)罢防,一般分為兩種數(shù)據(jù)
非結(jié)構(gòu)化數(shù)據(jù):數(shù)據(jù)的內(nèi)容整體沒有固定的格式和語法規(guī)范
結(jié)構(gòu)化數(shù)據(jù):數(shù)據(jù)的內(nèi)容有固定的語法規(guī)范,按照一定的結(jié)構(gòu)進(jìn)行組織管理
這兩種數(shù)據(jù)都分別表示什么樣的數(shù)據(jù)呢唉侄,分別應(yīng)該通過什么樣的方式進(jìn)行處理呢篙梢,這是爬蟲在采集完數(shù)據(jù)之后,針對數(shù)據(jù)進(jìn)行篩選必須要進(jìn)行的操作
接下來美旧,了解兩種不同的數(shù)據(jù)的表現(xiàn)形式
- 非結(jié)構(gòu)化數(shù)據(jù)
無格式字符串?dāng)?shù)據(jù):用戶名渤滞、郵箱、賬號榴嗅、電話號碼妄呕、地址、電影名稱嗽测、評分绪励、評論肿孵、商品名稱等等
- 結(jié)構(gòu)化數(shù)據(jù)
帶有一定的格式的數(shù)據(jù):HTML網(wǎng)頁文檔、XML網(wǎng)頁文檔疏魏、JSON等等
第三停做,對于不同的數(shù)據(jù),進(jìn)行有效數(shù)據(jù)篩選時(shí)大莫,應(yīng)該分別怎么進(jìn)行操作呢
非結(jié)構(gòu)化數(shù)據(jù):由于沒有任何固定的格式蛉腌,只能根據(jù)字符出現(xiàn)的規(guī)律進(jìn)行動態(tài)匹配的方式來完成數(shù)據(jù)的提取:正則表達(dá)式
結(jié)構(gòu)化數(shù)據(jù):由于數(shù)據(jù)本身存在一定的規(guī)律性只厘,可以通過針對這些規(guī)律的分析工具進(jìn)行數(shù)據(jù)的提壤哟浴:正則表達(dá)式、Xpath羔味、BeautifulSoup4河咽、select、css等等
2.正則表達(dá)式
正則表達(dá)式是一門單獨(dú)的技術(shù)赋元,在實(shí)際操作過程中由于它優(yōu)雅的字符匹配特性忘蟹,各種編程語言都陸續(xù)支持正則表達(dá)式的操作方式,Python中通過內(nèi)建模塊re進(jìn)行正則表達(dá)式的處理搁凸,大致按照如下三個(gè)步驟進(jìn)行數(shù)據(jù)的操作:
確定源數(shù)據(jù):獲取整體數(shù)據(jù)
按照目標(biāo)數(shù)據(jù)定義正則表達(dá)式匹配規(guī)則
從整體數(shù)據(jù)中匹配符合要求的數(shù)據(jù)
正則表達(dá)式的處理媚值,最核心的是先掌握正則表達(dá)式的語法和匹配規(guī)則,根據(jù)實(shí)際操作的不同需要坪仇,正則表達(dá)式定義了不同的數(shù)據(jù)匹配方式
匹配規(guī)則 | 規(guī)則描述 | |||
---|---|---|---|---|
\ | 將下一個(gè)字符標(biāo)記為一個(gè)特殊字符、或一個(gè)原義字符垃你、或一個(gè)向后引用低矮、或一個(gè)八進(jìn)制轉(zhuǎn)義符赶促。例如,“n”匹配字符“n”∫氚“\n”匹配一個(gè)換行符。串行“\”匹配“\”而“(”則匹配“(”浪秘。 | |||
^ | 匹配輸入字符串的開始位置评架。如果設(shè)置了RegExp對象的Multiline屬性,^也匹配“\n”或“\r”之后的位置锨亏。 | |||
$ | 匹配輸入字符串的結(jié)束位置痴怨。如果設(shè)置了RegExp對象的Multiline屬性,$也匹配“\n”或“\r”之前的位置器予。 | |||
* | 匹配前面的子表達(dá)式零次或多次浪藻。例如,zo能匹配“z”以及“zoo”乾翔。等價(jià)于{0,}爱葵。 | |||
+ | 匹配前面的子表達(dá)式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”萌丈,但不能匹配“z”赞哗。+等價(jià)于{1,}。 | |||
? | 匹配前面的子表達(dá)式零次或一次辆雾。例如肪笋,“do(es)?”可以匹配“does”或“does”中的“do”。?等價(jià)于{0,1}乾颁。 | |||
{n} | n是一個(gè)非負(fù)整數(shù)涂乌。匹配確定的n次。例如英岭,“o{2}”不能匹配“Bob”中的“o”湾盒,但是能匹配“food”中的兩個(gè)o。 | |||
{n,} | n是一個(gè)非負(fù)整數(shù)诅妹。至少匹配n次罚勾。例如,“o{2,}”不能匹配“Bob”中的“o”吭狡,但能匹配“foooood”中的所有o尖殃。“o{1,}”等價(jià)于“o+”划煮∷头幔“o{0,}”則等價(jià)于“o*”。 | |||
{n,m} | m和n均為非負(fù)整數(shù)弛秋,其中n<=m器躏。最少匹配n次且最多匹配m次。例如蟹略,“o{1,3}”將匹配“fooooood”中的前三個(gè)o登失。“o{0,1}”等價(jià)于“o?”挖炬。請注意在逗號和兩個(gè)數(shù)之間不能有空格揽浙。 | |||
? | 當(dāng)該字符緊跟在任何一個(gè)其他限制符(*,+,?,{n}意敛,{n,}馅巷,{n,m})后面時(shí),匹配模式是非貪婪的草姻。非貪婪模式盡可能少的匹配所搜索的字符串令杈,而默認(rèn)的貪婪模式則盡可能多的匹配所搜索的字符串。例如碴倾,對于字符串“oooo”逗噩,“o+?”將匹配單個(gè)“o”掉丽,而“o+”將匹配所有“o”。 | |||
. | 匹配除“\n”之外的任何單個(gè)字符异雁。要匹配包括“\n”在內(nèi)的任何字符捶障,請使用像“(.\n)”的模式。 | |||
(pattern) | 匹配pattern并獲取這一匹配纲刀。所獲取的匹配可以從產(chǎn)生的Matches集合得到项炼,在VBScript中使用SubMatches集合,在JScript中則使用$0…$9屬性示绊。要匹配圓括號字符锭部,請使用“\(”或“\)”。 | |||
(?:pattern) | 匹配pattern但不獲取匹配結(jié)果面褐,也就是說這是一個(gè)非獲取匹配拌禾,不進(jìn)行存儲供以后使用。這在使用或字符“( | )”來組合一個(gè)模式的各個(gè)部分是很有用展哭。例如“industr(?:y | ies)”就是一個(gè)比“industry | industries”更簡略的表達(dá)式湃窍。 |
(?=pattern) | 正向肯定預(yù)查,在任何匹配pattern的字符串開始處匹配查找字符串匪傍。這是一個(gè)非獲取匹配您市,也就是說,該匹配不需要獲取供以后使用役衡。例如茵休,“Windows(?=95 | 98 | NT | 2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”手蝎。預(yù)查不消耗字符榕莺,也就是說,在一個(gè)匹配發(fā)生后柑船,在最后一次匹配之后立即開始下一次匹配的搜索帽撑,而不是從包含預(yù)查的字符之后開始泼各。 |
(?!pattern) | 正向否定預(yù)查鞍时,在任何不匹配pattern的字符串開始處匹配查找字符串。這是一個(gè)非獲取匹配扣蜻,也就是說逆巍,該匹配不需要獲取供以后使用。例如“Windows(?!95 | 98 | NT | 2000)”能匹配“Windows3.1”中的“Windows”莽使,但不能匹配“Windows2000”中的“Windows”锐极。預(yù)查不消耗字符,也就是說芳肌,在一個(gè)匹配發(fā)生后灵再,在最后一次匹配之后立即開始下一次匹配的搜索肋层,而不是從包含預(yù)查的字符之后開始 |
(?<=pattern) | 反向肯定預(yù)查,與正向肯定預(yù)查類擬翎迁,只是方向相反栋猖。例如,“(?<=95 | 98 | NT | 2000)Windows”能匹配“2000Windows”中的“Windows”汪榔,但不能匹配“3.1Windows”中的“Windows”蒲拉。 |
(?x | y | 匹配x或y。例如痴腌,“z | food”能匹配“z”或“food”雌团。“(z | f)ood”則匹配“zood”或“food”士聪。 |
[xyz] | 字符集合锦援。匹配所包含的任意一個(gè)字符。例如戚嗅,“[abc]”可以匹配“plain”中的“a”雨涛。 | |||
[^xyz] | 負(fù)值字符集合。匹配未包含的任意字符懦胞。例如替久,“[^abc]”可以匹配“plain”中的“p”。 | |||
[a-z] | 字符范圍躏尉。匹配指定范圍內(nèi)的任意字符蚯根。例如,“[a-z]”可以匹配“a”到“z”范圍內(nèi)的任意小寫字母字符胀糜。 | |||
[^a-z] | 負(fù)值字符范圍颅拦。匹配任何不在指定范圍內(nèi)的任意字符。例如教藻,“[^a-z]”可以匹配任何不在“a”到“z”范圍內(nèi)的任意字符距帅。 | |||
\b | 匹配一個(gè)單詞邊界,也就是指單詞和空格間的位置括堤。例如碌秸,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”悄窃。 | |||
\B | 匹配非單詞邊界讥电。“er\B”能匹配“verb”中的“er”轧抗,但不能匹配“never”中的“er”恩敌。 | |||
\cx | 匹配由x指明的控制字符。例如横媚,\cM匹配一個(gè)Control-M或回車符纠炮。x的值必須為A-Z或a-z之一月趟。否則,將c視為一個(gè)原義的“c”字符恢口。 | |||
\d | 匹配一個(gè)數(shù)字字符狮斗。等價(jià)于[0-9]。 | |||
\D | 匹配一個(gè)非數(shù)字字符弧蝇。等價(jià)于[^0-9]碳褒。 | |||
\f | 匹配一個(gè)換頁符。等價(jià)于\x0c和\cL看疗。 | |||
\n | 匹配一個(gè)換行符沙峻。等價(jià)于\x0a和\cJ。 | |||
\r | 匹配一個(gè)回車符两芳。等價(jià)于\x0d和\cM摔寨。 | |||
\s | 匹配任何空白字符,包括空格怖辆、制表符是复、換頁符等等。等價(jià)于[ \f\n\r\t\v]竖螃。 | |||
\S | 匹配任何非空白字符淑廊。等價(jià)于[^ \f\n\r\t\v]。 | |||
\t | 匹配一個(gè)制表符特咆。等價(jià)于\x09和\cI季惩。 | |||
\v | 匹配一個(gè)垂直制表符。等價(jià)于\x0b和\cK腻格。 | |||
\w | 匹配包括下劃線的任何單詞字符画拾。等價(jià)于“[A-Za-z0-9_]”。 | |||
\W | 匹配任何非單詞字符菜职。等價(jià)于“[^A-Za-z0-9_]”青抛。 | |||
\xn | 匹配n,其中n為十六進(jìn)制轉(zhuǎn)義值酬核。十六進(jìn)制轉(zhuǎn)義值必須為確定的兩個(gè)數(shù)字長蜜另。例如,“\x41”匹配“A”愁茁〔锨眨“\x041”則等價(jià)于“\x04&1”亭病。正則表達(dá)式中可以使用ASCII編碼鹅很。. | |||
\num | 匹配num,其中num是一個(gè)正整數(shù)罪帖。對所獲取的匹配的引用促煮。例如邮屁,“(.)\1”匹配兩個(gè)連續(xù)的相同字符。 | |||
\n | 標(biāo)識一個(gè)八進(jìn)制轉(zhuǎn)義值或一個(gè)向后引用菠齿。如果\n之前至少n個(gè)獲取的子表達(dá)式佑吝,則n為向后引用。否則绳匀,如果n為八進(jìn)制數(shù)字(0-7)芋忿,則n為一個(gè)八進(jìn)制轉(zhuǎn)義值。 | |||
\nm | 標(biāo)識一個(gè)八進(jìn)制轉(zhuǎn)義值或一個(gè)向后引用疾棵。如果\nm之前至少有nm個(gè)獲得子表達(dá)式戈钢,則nm為向后引用。如果\nm之前至少有n個(gè)獲取是尔,則n為一個(gè)后跟文字m的向后引用殉了。如果前面的條件都不滿足,若n和m均為八進(jìn)制數(shù)字(0-7)拟枚,則\nm將匹配八進(jìn)制轉(zhuǎn)義值nm薪铜。 | |||
\nml | 如果n為八進(jìn)制數(shù)字(0-3),且m和l均為八進(jìn)制數(shù)字(0-7)恩溅,則匹配八進(jìn)制轉(zhuǎn)義值nml隔箍。 | |||
\un | 匹配n,其中n是一個(gè)用四個(gè)十六進(jìn)制數(shù)字表示的Unicode字符脚乡。例如鞍恢,\u00A9匹配版權(quán)符號(?)。 |
3. python操作正則表達(dá)式
python內(nèi)置了re模塊每窖,可以很方便快捷的操作正則表達(dá)式語法完成字符串的查詢匹配操作行為帮掉,需要注意的是通過re操作正則表達(dá)式的兩種表現(xiàn)形式
第一種方式主要是通過compile()函數(shù)根據(jù)給定的正則表達(dá)式編譯生成正則匹配對象,通過正則匹配對象完成字符串的查詢匹配操作過程
import re
#定義正則表達(dá)式窒典,通過compile()函數(shù)編譯
pattern = re.compile('正則表達(dá)式')
#核心操作函數(shù)
# 1.起始位置匹配一次:僅從指定的起始位置進(jìn)行匹配(默認(rèn)開頭位置)
#匹配成功返回匹配到的字符串蟆炊,表示目標(biāo)字符串是該字符串開頭的
#匹配失敗返回None
value = pattern.match(string[, start[ , end]])
# 2.全文匹配一次:從指定的起始位置開始匹配(默認(rèn)開頭位置)
#陸續(xù)對字符串中的所有字符進(jìn)行匹配
#匹配成功返回匹配到的字符串,表示目標(biāo)字符串中包含該字符串
#匹配失敗返回None
value = pattern.search(string[, start[, end]])
# 3.全文匹配
#從目標(biāo)字符串中查詢所有符合匹配規(guī)則的字符瀑志,并存儲到一個(gè)列表中
#匹配結(jié)束返回列表涩搓,包含匹配到的數(shù)據(jù)
#沒有匹配到數(shù)據(jù)返回空列表,否則返回包含所有匹配數(shù)據(jù)的列表
value_list = pattern.findall(string[, start[, end]])
# 4.全文匹配獲取迭代器
#從目標(biāo)字符串中查詢所有符合匹配規(guī)則的字符劈猪,并存儲到一個(gè)迭代器中
value_iter = pattern.finditer(string[, start[, end]])
# 5.字符串切割:根據(jù)指定的正則表達(dá)式切割目標(biāo)字符串并返回切割后的列表
value_list = pattern.split(string)
# 6.字符串替換:根據(jù)指定的匹配規(guī)則昧甘,將string中符合的字符串替換為value值,count是替換次數(shù)战得,默認(rèn)全部替換
value_replace = pattern.sub(value, string[, count])
通過正則匹配到的值對象value充边,可以通過指定的函數(shù)輸出匹配到的數(shù)據(jù)的信息
#輸出匹配到的數(shù)據(jù)
value.group()
#輸出匹配到的第一組數(shù)據(jù)
value.group(1)
#輸出匹配的第n組數(shù)據(jù):前提條件是在正則表達(dá)式中使用圓括號進(jìn)行了n次分組
value.group(n)
#輸出匹配數(shù)據(jù)的索引范圍
value.span()
#輸出匹配的第n組數(shù)據(jù)的索引范圍
value.span(n)
#輸出匹配的第n組數(shù)據(jù)的索引開始位置
value.start(n)
#輸出匹配的第n組數(shù)據(jù)的索引結(jié)束位置
value.end(n)
注意的是:在使用正則表達(dá)式時(shí),貪婪模式和懶惰模式的操作行為可以精確的匹配數(shù)據(jù)
通常情況下,正則表達(dá)式模式是貪婪模式進(jìn)行匹配的浇冰,如果需要精確匹配的情況下贬媒,在正常正則表達(dá)式后面添加一個(gè)?匹配符號即可!
#定義目標(biāo)字符串
>>> s = "helelo world"
#編譯正則匹配對象:這里我們只是想得到: lel
>>> pattern = re.compile('l*l')
#進(jìn)行數(shù)據(jù)匹配操作
>>> r = re.compile('l.*l')
#展示數(shù)據(jù)
>>> r.search(s).group()
#展示得到的數(shù)據(jù)肘习,顯然匹配的數(shù)據(jù)中包含了其他數(shù)據(jù)
'lelo worl'
#那么际乘,下面這個(gè)例子,貌似更加實(shí)際
>>> html = "
i am div
i am p
i am div too
"
#定義匹配規(guī)則漂佩,只是想匹配div中包含的數(shù)據(jù)
>>> pattern = re.compile("
.*
")
#打印展示數(shù)據(jù)
>>> pattern.search(html).group()
#顯示的數(shù)據(jù)脖含,明顯包含了不需要的數(shù)據(jù),這是貪婪模式
'
i am div
i am p
i am div
'
#重新定義
>>> html = "
i am div
i am p
i am div too
"
#修改過的正則表達(dá)式
>>> pattern = re.compile("
.*?
")
#匹配得到數(shù)據(jù)
>>> pattern.search(html).group()
#顯示的數(shù)據(jù)投蝉,包含的數(shù)據(jù)器赞,就是精確匹配到的數(shù)據(jù)
'
i am div
'
正則表達(dá)式案例操作:百度圖片搜索下載
4. Xpath
Xpath原本是在可擴(kuò)展標(biāo)記語言XML中進(jìn)行數(shù)據(jù)查詢的一種描述語言,可以很方便的在XML文檔中查詢到具體的數(shù)據(jù)墓拜;后續(xù)再發(fā)展過程中港柜,對于標(biāo)記語言都有非常友好的支持,如超文本標(biāo)記語言HTML咳榜。
在操作Xpath之前夏醉,首先需要了解一些基礎(chǔ)的技術(shù)術(shù)語
下面是一段常見的HTML代碼
一級標(biāo)題
標(biāo)題
標(biāo)題
標(biāo)題
標(biāo)題
內(nèi)容
內(nèi)容
內(nèi)容
內(nèi)容
根標(biāo)簽:在標(biāo)記語言中,處在最外層的一個(gè)標(biāo)簽就是根標(biāo)簽涌韩,根標(biāo)簽有且僅有一個(gè)畔柔,在上述代碼中\(zhòng)就是跟標(biāo)簽
父標(biāo)簽:和子標(biāo)簽對應(yīng),內(nèi)部包含了其他元素?cái)?shù)據(jù)臣樱,該標(biāo)簽就是內(nèi)部標(biāo)簽的父標(biāo)簽靶擦,如\是\的父標(biāo)簽,\又是\的父標(biāo)簽雇毫,某些說法中玄捕,父標(biāo)簽的父標(biāo)簽..被稱為上級標(biāo)簽或則先代標(biāo)簽或者先輩標(biāo)簽
子標(biāo)簽;和父標(biāo)簽對應(yīng)棚放,被包含的元素枚粘,就是外部元素的子標(biāo)簽,如\是\的子標(biāo)簽飘蚯,\標(biāo)簽是\的子標(biāo)簽馍迄,\是\的子標(biāo)簽;同樣的子標(biāo)簽的子標(biāo)簽局骤,也被稱為后代標(biāo)簽
兄弟標(biāo)簽:兩個(gè)或者多個(gè)處在相同級別的標(biāo)簽攀圈,有相同的父標(biāo)簽,如\和\是兄弟標(biāo)簽峦甩,\和\是兄弟標(biāo)簽赘来,\中的兩個(gè)\是兄弟標(biāo)簽等等
- Xpath描述語言的常見語法
和正則表達(dá)式相比較,Xpath使用最簡單的語法操作完成數(shù)據(jù)的查詢匹配操作
表達(dá)式 | 描述 |
---|---|
nodename | 選取此節(jié)點(diǎn)的所有子節(jié)點(diǎn)。 |
/ | 從根節(jié)點(diǎn)選取撕捍。 |
// | 從匹配選擇的當(dāng)前節(jié)點(diǎn)選擇文檔中的節(jié)點(diǎn),而不考慮它們的位置泣洞。 |
. | 選取當(dāng)前節(jié)點(diǎn)忧风。 |
.. | 選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)。 |
@ | 選取屬性球凰。 |
* | 匹配任何元素節(jié)點(diǎn)狮腿。 |
@* | 匹配任何屬性節(jié)點(diǎn)。 |
node() | 匹配任何類型的節(jié)點(diǎn)呕诉。 |
路徑表達(dá)式 | 結(jié)果 |
---|---|
html | 選取 html元素的所有子節(jié)點(diǎn)缘厢。 |
/html | 選取根元素 html。注釋:假如路徑起始于正斜杠( / )甩挫,則此路徑始終代表到某元素的絕對路徑贴硫! |
table/tr/td | 選取屬于 table的子元素的所有 td元素。 |
//div | //table | 選取所有的div或者table節(jié)點(diǎn) |
//table | 選取所有 table子元素伊者,而不管它們在文檔中的位置英遭。 |
html//div | 選擇屬于html元素的后代的所有div元素,而不管它們位于 html之下的什么位置亦渗。 |
//@href | 選取名為href的所有屬性挖诸。 |
通過如下的方式直接操作上面的文檔
路徑表達(dá)式 | 結(jié)果 |
---|---|
html | 選取 html元素的所有子節(jié)點(diǎn)。 |
/html | 選取根元素 html法精。注釋:假如路徑起始于正斜杠( / )多律,則此路徑始終代表到某元素的絕對路徑! |
table/tr/td | 選取屬于 table的子元素的所有 td元素搂蜓。 |
//div | //table | 選取所有的div或者table節(jié)點(diǎn) |
//table | 選取所有 table子元素狼荞,而不管它們在文檔中的位置。 |
html//div | 選擇屬于html元素的后代的所有div元素帮碰,而不管它們位于 html之下的什么位置粘秆。 |
//@href | 選取名為href的所有屬性。 |
標(biāo)簽條件篩選查詢匹配
路徑表達(dá)式 | 結(jié)果 |
---|---|
//table/tr[1] | 選取屬于table子元素的第一個(gè) tr元素收毫。 |
//table/tr[last()] | 選取屬于 table子元素的最后一個(gè) tr元素攻走。 |
//table/tr[last()-1] | 選取屬于 table子元素的倒數(shù)第二個(gè) tr元素。 |
//table/tr[position()<3] | 選取最前面的兩個(gè)屬于 table元素的子元素的tr元素此再。 |
//td[@width] | 選取所有擁有名為 width的屬性的 td元素昔搂。 |
//td[@width='100'] | 選取所有 td元素,且這些元素?fù)碛袑傩詗idth并且值為100输拇。 |
//tr//td[span>10000] | 選取tr元素的所有td子元素摘符,并且其中的span元素的值須大于10000。 |
同樣,Xpath支持?jǐn)?shù)據(jù)運(yùn)算操作
運(yùn)算符 | 描述 | 實(shí)例 | 返回值 |
---|---|---|---|
+ | 加法 | 6 + 4 | 10 |
- | 減法 6 - 4 | 2 | |
* | 乘法 6 * 4 | 24 | |
div | 除法 8 div 4 | 2 | |
= | 等于 | price=9.80 | 如果 price是 9.80逛裤,則返回 true瘩绒。如果 price是 9.90,則返回 false带族。 |
!= | 不等于 | price!=9.80 | 如果 price是 9.90锁荔,則返回 true。如果 price是9.80蝙砌,則返回 false阳堕。 |
< | 小于 | price<9.80 | 如果 price是 9.00,則返回 true择克。如果 price是 9.90恬总,則返回 false。 |
<= | 小于或等于 | price<=9.80 | 如果 price是 9.00肚邢,則返回 true壹堰。如果 price是 9.90,則返回 false骡湖。 |
> | 大于 | price>9.80 | 如果 price是 9.90缀旁,則返回 true。如果 price是 9.80勺鸦,則返回 false并巍。 |
>= | 大于或等于 | price>=9.80 | 如果 price是 9.90,則返回 true换途。如果 price是 9.70懊渡,則返回 false。 |
or | 或 | price=9.80 or price=9.70 | 如果 price是 9.80军拟,則返回 true剃执。如果 price是 9.50,則返回 false懈息。 |
and | 與 | price>9.00 and price<9.90 | 如果 price是 9.80肾档,則返回 true。如果 price是 8.50辫继,則返回 false怒见。 |
mod | 計(jì)算除法的余數(shù) | 5 mod 2 | 1 |
xpath在瀏覽器中進(jìn)行測試時(shí),可以給谷歌瀏覽器安裝一個(gè)插件Xpath Helper插件姑宽;就可以直接在瀏覽器中通過xpath語法來完成對數(shù)據(jù)的匹配測試
測試通過的xpath語法遣耍,就可以直接在程序中使用了!
5.python操作Xpath
python第三方模塊lxml可以對Xpath有友好的支持炮车,lxml是C實(shí)現(xiàn)的一種高性能python用于HTML/XML的解析模塊舵变,可以通過Xpath語法在html文檔數(shù)據(jù)中進(jìn)行指定表達(dá)式數(shù)據(jù)的索引查詢
*簡單etree操作
# -*- coding:utf-8 -*-
from lxml import etree
#模擬得到爬蟲數(shù)據(jù)
content = """
個(gè)人簡介
姓名:某某某
住址:中國 鄉(xiāng)下
座右銘:豈能盡如人意酣溃,但求無愧于心
"""
#轉(zhuǎn)換成html數(shù)據(jù)
# html = etree.parse("index.html")#從文件中直接加載html數(shù)據(jù)
html = etree.HTML(content)#通過etree.HTML()函數(shù)將字符串轉(zhuǎn)換成HTML文檔對象
print dir(html)#查看文檔對象的所有函數(shù)
print html.getchildren()#查看文檔對象根節(jié)點(diǎn)的所有子節(jié)點(diǎn)
#轉(zhuǎn)換成字符數(shù)據(jù)
str_html = etree.tostring(html)#將HTML文檔對象轉(zhuǎn)換成字符串
print type(str_html)#查看輸出類型
print str_html#查看輸出數(shù)據(jù)
- xpath操作
# -*- coding:utf-8 -*-
from lxml import etree
#模擬得到爬蟲數(shù)據(jù)
content = u"""
個(gè)人簡介
姓名:某某某
住址:中國 鄉(xiāng)下
座右銘:豈能盡如人意,但求無愧于心
"""
#將爬取到的數(shù)據(jù)轉(zhuǎn)換成HTML文檔
html = etree.HTML(content)
#查詢所有的p標(biāo)簽
p_x = html.xpath("http://p")
print(p_x)
#查詢所有Name屬性的值
v_attr_name= html.xpath("http://@name")
print(v_attr_name)
#查詢所有包含name屬性的標(biāo)簽
e_attr_name = html.xpath("http://*[@name]")
print(e_attr_name)
#查詢所有包含name屬性纪隙,并且name屬性值為desc的標(biāo)簽
e_v_attr_name = html.xpath("http://*[@name='desc']")
print(e_v_attr_name)
#查詢所有p標(biāo)簽的文本內(nèi)容,不包含子標(biāo)簽
p_t = html.xpath("http://p")
for p in p_t:
print (p.text)
#查詢多個(gè)p標(biāo)簽下的所有文本內(nèi)容赊豌,包含子標(biāo)簽中的文本內(nèi)容
p_m_t = html.xpath("http://p")
for p2 in p_m_t:
print(p2.xpath("string(.)"))
案例操作:爬蟲智聯(lián)招聘中前10頁的某個(gè)工作崗位名稱、薪水绵咱、公司信息
6. BeautifulSoup4
BeautifulSoup也是一種非常優(yōu)雅的專門用于進(jìn)行HTML/XML數(shù)據(jù)解析的一種描述語言碘饼,可以很好的分析和篩選HTML/XML這樣的標(biāo)記文檔中的指定規(guī)則數(shù)據(jù)
在數(shù)據(jù)篩選過程中其基礎(chǔ)技術(shù)是通過封裝HTML DOM樹實(shí)現(xiàn)的一種DOM操作,通過加載網(wǎng)頁文檔對象的形式麸拄,從文檔對象模型中獲取目標(biāo)數(shù)據(jù)
BeautifulSoup操作簡單易于上手派昧,在很多對于數(shù)據(jù)篩選性能要求并不是特別苛刻的項(xiàng)目中經(jīng)常使用黔姜,目前市場流行的操作版本是BeautifulSoup4拢切,經(jīng)常稱BS4
Xpath和BeautifulSoup
Xpath和BeautifulSoup都是基于DOM的一種操作模式
不同點(diǎn)在于加載文檔對象模型DOM時(shí)出現(xiàn)的文檔節(jié)點(diǎn)遍歷查詢操作過程,Xpath在進(jìn)行遍歷操作時(shí)針對描述語言指定的語法結(jié)構(gòu)進(jìn)行局部DOM對象樹的遍歷得到具體的數(shù)據(jù)秆吵,但是BS4在操作過程中淮椰,會將整個(gè)文檔樹進(jìn)行加載然后進(jìn)行查詢匹配操作,使用過程中消耗資源較多纳寂,處理性能相對Xpath較低
那么為什么要用BS4呢主穗?因?yàn)椋形撸銐蚝唵?
描述語言 | 處理效率 | 上手程度 |
---|---|---|
正則表達(dá)式 | 效率非常高 | 困難 |
Xpath | 效率很高 | 正常 |
BS4 | 效率較高 | 簡單 |
BS4本身是一種對描述語言進(jìn)行封裝的函數(shù)操作模塊忽媒,通過提供面向?qū)ο蟮牟僮鞣绞綄⑽臋n對象中的各種節(jié)點(diǎn)、標(biāo)簽腋粥、屬性晦雨、內(nèi)容等等都封裝成了python中對象的屬性,在查詢操作過程中隘冲,通過調(diào)用指定的函數(shù)直接進(jìn)行數(shù)據(jù) 匹配檢索操作,非常的簡單非常的靈活。
一般BS4將HTML文檔對象會轉(zhuǎn)換成如下四種類型組合的文檔樹
Tag:標(biāo)簽對象
NavigableString:字符內(nèi)容操作對象
BeautifulSoup:文檔對象
Comment:特殊類型的NavigableString
說道這里航夺,其實(shí)都是太多的理論性語法划提,BS4不同于正則和Xpath,沒有什么基礎(chǔ)語法結(jié)構(gòu)罗珍,它封裝的對象以及對象的屬性操作洽腺,才是BS4不同凡響的核心價(jià)值
let's上干貨
7. python操作BeautifulSoup4
python中對于BeautifulSoup的支持,通過安裝第三方模塊來發(fā)揮它最好的操作
$ pip install beautifulsoup4
*入門第一彈:了解BeautifulSoup4
# coding:utf-8
#引入解析模塊BS4
from bs4 import BeautifulSoup
#從文件中加載html網(wǎng)頁覆旱,指定HTML解析器使用lxml
#默認(rèn)不指定的情況下已脓,BS4會自動匹配當(dāng)前系統(tǒng)中最優(yōu)先的解析器
soup = BeautifulSoup(open("index.html"), "lxml")
#如果是爬蟲獲取到的字符數(shù)據(jù),直接交給BS4就OK拉
# soup = BeatufulSoup(spider_content, "lxml")
#打印BeautifulSoup文檔對象通殃,得到的是文檔樹內(nèi)容
print(soup)
#打印類型:
print(type(soup))
*入門第二彈:操作標(biāo)簽度液、屬性厕宗、內(nèi)容
# coding:utf-8
from bs4 import BeautifulSoup
#得到構(gòu)建的文檔對象
soup = BeautifulSoup(open("index.html"), "lxml")
# Tag操作
# 1.獲取標(biāo)簽
print(soup.title) #
print(soup.p) #
姓名:大牧
#只返回第一個(gè)匹配到的標(biāo)簽對象
print(soup.span) # 大牧
# 2.獲取標(biāo)簽的屬性
print(soup.p.attrs) # {}:得到屬性和值的字典
print(soup.span.attrs) # {'id': 'name'}:得到屬性和值的字典
print(soup.span['id']) # name:得到指定屬性的值
soup.span['id'] = "real_name"
print(soup.span['id']) # real_name :可以方便的在BS4中直接對文檔進(jìn)行修改
# 3.獲取標(biāo)簽的內(nèi)容
print(soup.head.string) #文章標(biāo)題:如果標(biāo)簽中只有一個(gè)子標(biāo)簽~返回子標(biāo)簽中的文本內(nèi)容
print(soup.p.string) # None:如果標(biāo)簽中有多個(gè)子標(biāo)簽,返回None
print(soup.span.string) #大牧:直接返回包含的文本內(nèi)容
*入門第三彈:操作子節(jié)點(diǎn)
# coding:utf-8
#引入BS4操作模塊
from bs4 import BeautifulSoup
#加載網(wǎng)頁文檔堕担,構(gòu)建文檔對象
soup = BeautifulSoup(open("index.html"), "lxml")
print(dir(soup))
print(soup.contents)#得到文檔對象中所有子節(jié)點(diǎn)
print(soup.div.contents)#得到匹配到的第一個(gè)div的子節(jié)點(diǎn)列表
print(soup.div.children)#得到匹配到的第一個(gè)div的子節(jié)點(diǎn)列表迭代器
# for e1 in soup.div.children:
# print("-->", e1)
print(soup.div.descendants)#得到匹配到的第一個(gè)div的子節(jié)點(diǎn)迭代器,所有后代節(jié)點(diǎn)單獨(dú)一個(gè)一個(gè)列出
# for e2 in soup.div.descendants:
# print("==>", e2)
*入門第四彈:面向?qū)ο蟮腄OM匹配
# coding:utf-8
#引入BS4模塊
from bs4 import BeautifulSoup
#加載文檔對象
soup = BeautifulSoup(open("../index.html"), "lxml")
# DOM文檔樹查詢
#核心函數(shù)~請對比javasript dom結(jié)構(gòu)了解它的方法
#如:findAllPrevious()/findAllNext()/findAll()/findPrevious()/findNext()等等
# findAll()為例
# 1.查詢指定的字符串
res1 = soup.findAll("p")#查詢所有包含p字符的標(biāo)簽
print(res1)
# 2.正則表達(dá)式
import re
res2 = soup.findAll(re.compile(r"d+"))#查詢所有包含d字符的標(biāo)簽
print(res2)
# 3.列表:選擇
res3 = soup.findAll(["div", "h1"])#查詢所有的div或者h(yuǎn)1標(biāo)簽
print(res3)
# 4.關(guān)鍵字參數(shù)
res4 = soup.findAll(id="name")#查詢屬性為id="name"的標(biāo)簽
print(res4)
# 5.內(nèi)容匹配
res5 = soup.findAll(text=u"男")#直接匹配內(nèi)容中的字符已慢,必須保證精確匹配
print(res5)
res6 = soup.findAll(text=[u"文章標(biāo)題", u"大牧"])#查詢包含精確內(nèi)容的所有的標(biāo)簽
print(res6)
res7 = soup.findAll(text=re.compile(u"大+"))#通過正則表達(dá)式進(jìn)行模糊匹配
print(res7)
*入門第五彈:又見CSS
# coding:utf-8
#引入BS模塊
from bs4 import BeautifulSoup
#加載網(wǎng)頁構(gòu)建文檔對象
soup = BeautifulSoup(open("index.html"), "lxml")
# 1. CSS標(biāo)簽選擇器:根據(jù)標(biāo)簽名稱查詢標(biāo)簽對象
res1 = soup.select("span")
print(res1)
# 2. CSS ID選擇器:根據(jù)ID查詢標(biāo)簽對象
res2 = soup.select("#gender")
print(res2)
# 3. CSS類選擇器:根據(jù)class屬性查詢標(biāo)簽對象
res3 = soup.select(".intro")
print(res3)
# 4. CSS屬性選擇器
res41 = soup.select("span[id]")
print(res41)
res42 = soup.select("span[id='gender']")
print(res42)
# 5. CSS包含選擇器
res5 = soup.select("p span#name")
print(res5)
# 6.得到標(biāo)簽內(nèi)容
res6 = soup.select("p > span.intro")
print(res6[0].string)
print(res6[0].getText())