關於Python的爬蟲的一些數據提取的方法總結
第一種 : 正則表達式
- 正則表達式是 對於it來說最常用的一個,就是用事先定義好的一些特定的字符,及這些特定的組合,組成一個"規則字符串",
- 規則
模式 | 描述 |
---|---|
^ | 匹配字符串的開頭 |
$ | 匹配字符串的末尾 |
. | 匹配任意字符,除了換行符,當re.DOTALL標記被指定時,則可以匹配包括換行符的任意字符 |
[…] | 用來表示一組字符,單獨列出:[amk] 匹配 ‘a’,‘m’或’k’ |
[^…] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符 |
re* | 匹配0個或多個的表達式 |
re+ | 匹配1個或多個的表達式 |
re? | 匹配0個或1個由前面的正則表達式定義的片段,非貪婪方式 |
re{ n} | |
re{ n,} | 精確匹配n個前面表達式 |
re{ n, m} | 匹配 n 到 m 次由前面的正則表達式定義的片段,貪婪方式 |
a | b |
(re) | G匹配括號內的表達式,也表示一個組 |
(?imx) | 正則表達式包含三種可選標志:i, m, 或 x 。只影響括號中的區域 |
(?-imx) | 正則表達式關閉 i, m, 或 x 可選標志。只影響括號中的區域 |
(?: re) | 類似 (…), 但是不表示一個組 |
(?imx: re) | 在括號中使用i, m, 或 x 可選標志 |
(?-imx: re) | 在括號中不使用i, m, 或 x 可選標志 |
(?#…) | 注釋 |
(?= re) | 前向肯定界定符。如果所含正則表達式,以 … 表示,在當前位置成功匹配時成功,否則失敗。但一旦所含表達式已經嘗試,匹配引擎根本沒有提高;模式的剩余部分還要嘗試界定符的右邊。 |
(?! re) | 前向否定界定符。與肯定界定符相反;當所含表達式不能在字符串當前位置匹配時成功 |
(?> re) | 匹配的獨立模式,省去回溯 |
\w | 匹配字母數字及下划線 |
\W | 匹配非字母數字及下划線 |
\s | 匹配任意空白字符,等價於 [\t\n\r\f]. |
\S | 匹配任意非空字符 |
\d | 匹配任意數字,等價於 [0-9] |
\D | 匹配任意非數字 |
\A | 匹配字符串開始 |
\Z | 匹配字符串結束,如果是存在換行,只匹配到換行前的結束字符串。c |
\z | 匹配字符串結束 |
\G | 匹配最后匹配完成的位置 |
\b | 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’ |
\B | 匹配非單詞邊界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’ |
\n, \t, 等. | 匹配一個換行符。匹配一個制表符。等 |
\1…\9 | 匹配第n個分組的內容 |
\10 | 匹配第n個分組的內容,如果它經匹配。否則指的是八進制字符碼的表達式 |
[\u4e00-\u9fa5] | 中文 |
2. 正則表達式相關注解
2.1 數量詞的貪婪模式與非貪婪模式
正則表達式通常用於在文本中查找匹配的字符串
Python里數量詞默認是貪婪的(在少數語言里也可能是默認非貪婪),總是嘗試匹配盡可能多的字符;非貪婪的則相反,總是嘗試匹配盡可能少的字符
例如:正則表達式”ab*”如果用於查找”abbbc”,將找到”abbb”。而如果使用非貪婪的數量詞”ab*?”,將找到”a”
2.2 常用方法
- re.match
- re.match 嘗試從字符串的起始位置匹配一個模式,如果不是起始位置匹配成功的話,match()就返回none
- 函數語法:
re.match(pattern, string, flags=0)
- re.search
- re.search 掃描整個字符串並返回第一個成功的匹配。
- 函數語法:
re.search(pattern, string, flags=0)
- re.sub
- re.sub 替換字符串
re.sub(pattern,replace,string)
- re.sub 替換字符串
- re.findall
- re.findall 查找全部
re.findall(pattern,string,flags=0)
- re.findall 查找全部
第二種:bs4 的使用
- bs4 就是Beautiful Soup 的簡稱,這是一個工具箱,通過解析文檔為用戶提供需要抓取的數據,
- 使用這個不需要在編碼的上面考慮,他會自動轉換為utf-8編碼。
- 但是使用這個的前提的就是網頁是完整的,但是現在的網頁大多規范化,所以都是可以用的
- 官網: http://beautifulsoup.readthedocs.io/zh_CN/latest/
- bs4 必須使用一種解析器,如果你沒有安裝其他的HTML解析器,他會默認使用自帶的解析器,但是lxml 解析器更加強大,速度更快,推薦安裝
- 對於 四種解析器的對比
解析器 | 使用方法 | 優勢 | 劣勢 |
---|---|---|---|
Python標准庫 | BeautifulSoup(markup, “html.parser”) | 1. Python的內置標准庫 2. 執行速度適中 3.文檔容錯能力強 | Python 2.7.3 or 3.2.2)前 的版本中文檔容錯能力差 |
lxml HTML 解析器 | BeautifulSoup(markup, “lxml”) | 1. 速度快 2.文檔容錯能力強 | 需要安裝C語言庫 |
lxml XML 解析器 | BeautifulSoup(markup, [“lxml”, “xml”]) BeautifulSoup(markup, “xml”) | 1. 速度快 2.唯一支持XML的解析器 3.需要安裝C語言庫 | |
html5lib | BeautifulSoup(markup, “html5lib”) | 1. 最好的容錯性 2.以瀏覽器的方式解析文檔 3.生成HTML5格式的文檔 4.速度慢 | 不依賴外部擴展 |
- 對於bs4 有四大對象種類
- Tag
- navigableString
- BeautifulSoup
- Comment
- 更加細致的編寫的方法,可以去官網查看
第三種 : Xpath
-
相對於其他的方法,我更加的喜歡這種方法,因為更加的方便
-
xpath 是一門在XML文檔中查找信息的語言,
-
是以節點來表達關系的
- 父(Parent)
- 子(Children)
- 同胞(Sibling)
- 先輩(Ancestor)
- 后代(Descendant)
-
選取節點
- 常用的路徑表達式
表達式 | 描述 |
---|---|
nodename | 選取此節點的所有子節點 |
/ | 從根節點選取 |
// | 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置 |
. | 選取當前節點 |
… | 選取當前節點的父節點 |
@ | 選取屬性 |
- 通配符
XPath 通配符可用來選取未知的 XML 元素。
通配符 | 描述 | 舉例 | 結果 |
---|---|---|---|
* | 匹配任何元素節點 | xpath(‘div/*’) | 獲取div下的所有子節點 |
@* | 匹配任何屬性節點 | xpath(‘div[@*]’) | 選取所有帶屬性的div節點 |
node() | 匹配任何類型的節點 |
- 選取若干路徑
通過在路徑表達式中使用“|”運算符,您可以選取若干個路徑
表達式 | 結果 |
---|---|
xpath(’//div| //table’) |
獲取所有的div與table節點 |
- 謂語
謂語被嵌在方括號內,用來查找某個特定的節點或包含某個制定的值的節點
表達式 | 結果 |
---|---|
xpath(’/body/div[1]’) | 選取body下的第一個div節點 |
xpath(’/body/div[last()]’) | 選取body下最后一個div節點 |
xpath(’/body/div[last()-1]’) | 選取body下倒數第二個節點 |
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節點 |
第四種 : jsonPath
這個是Python自帶的輕量級的數據交換格式,這個與XML相較比不相上下
3.1 json.loads()
- Python中的json 模塊
- 提供了四個功能 : dumps,dump,loads,load 用於字符串和Python數據類型進行轉換
把Json格式字符串解碼轉換成Python對象 從json到python的類型轉化對照如下:
import json
strList = '[1, 2, 3, 4]'
strDict = '{"city": "北京", "name": "范爺"}'
json.loads(strList)
# [1, 2, 3, 4]
json.loads(strDict) # json數據自動按Unicode存儲
# {u'city': u'\u5317\u4eac', u'name': u'\u5927\u732b'}
3.2 json.dumps()
實現python類型轉化為json字符串,返回一個str對象 把一個Python對象編碼轉換成Json字符串
從python原始類型向json類型的轉化對照如下:
# json_dumps.py
import json
listStr = [1, 2, 3, 4]
tupleStr = (1, 2, 3, 4)
dictStr = {"city": "北京", "name": "范爺"}
json.dumps(listStr)
# '[1, 2, 3, 4]'
json.dumps(tupleStr)
# '[1, 2, 3, 4]'
# 注意:json.dumps() 序列化時默認使用的ascii編碼
# 添加參數 ensure_ascii=False 禁用ascii編碼,按utf-8編碼
json.dumps(dictStr)
# '{"city": "\\u5317\\u4eac", "name": "\\u5927\\u5218"}'
print(json.dumps(dictStr, ensure_ascii=False))
# {"city": "北京", "name": "范爺"}
3.3 json.dump()
將Python內置類型序列化為json對象后寫入文件
import json
listStr = [{"city": "北京"}, {"name": "范爺"}]
json.dump(listStr, open("listStr.json","w"), ensure_ascii=False)
dictStr = {"city": "北京", "name": "范爺"}
json.dump(dictStr, open("dictStr.json","w"), ensure_ascii=False)
使用這個的好處
-
如果網頁是用ajax來進行 數據交互的,
-
使用jsonPath 就是可以直接使用url 來進行獲取數據,相對於其他就更加的方便
-
示例
- 我們以拉勾網城市JSON文件 http://www.lagou.com/lbs/getAllCitySearchLabels.json 為例,獲取所有城市
from urllib.request import urlopen
from urllib.request import Request
import jsonpath
import json
url = 'http://www.lagou.com/lbs/getAllCitySearchLabels.json'
request =Request(url)
response = urlopen(request)
html = response.read()
# 把json格式字符串轉換成python對象
jsonobj = json.loads(html)
# 從根節點開始,匹配name節點
citylist = jsonpath.jsonpath(jsonobj,'$..name')
print(citylist)
print(type(citylist))
fp = open('city.json','w')
content = json.dumps(citylist, ensure_ascii=False)
print(content)
fp.write(content)
fp.close()