黑馬python2.7的爬蟲2-非結構化資料與結構化資料提取
非結構化資料與結構化資料提取
抓取的是某個網站或者某個應用的內容,提取有用的價值。內容一般分為兩部分,非結構化的資料 和 結構化的資料。
- 非結構化資料:先有資料,再有結構,
- 結構化資料:先有結構、再有資料
- 不同型別的資料,我們需要採用不同的方式來處理。
1、非結構化的資料處理
文字、電話號碼、郵箱地址
- 正則表示式
HTML 檔案
- 正則表示式
- XPath
- CSS選擇器
2、結構化的資料處理
JSON 檔案
- JSON Path
- 轉化成Python型別進行操作(json類)
XML 檔案
- 轉化成Python型別(xmltodict)
- XPath
- CSS選擇器
- 正則表示式
爬蟲一共就四個主要步驟:
- 明確目標 (要知道你準備在哪個範圍或者網站去搜索)
- 爬 (將所有的網站的內容全部爬下來)
- 取 (去掉對我們沒用處的資料)
- 處理資料(按照我們想要的方式儲存和使用)
1、正則表示式
正則表示式和另一個字串可以匹配和過濾
正則有字元.,字符集\d,數量詞*,邊界匹配^,分組|,特殊構造組成。
使用步驟:編譯……查詢……匹配
Pattern 物件的一些常用方法主要有:
- match 方法:從起始位置開始查詢,一次匹配
- search 方法:從任何位置開始查詢,一次匹配
- findall 方法:全部匹配,返回列表
- finditer 方法:全部匹配,返回迭代器
- split 方法:分割字串,返回列表
- sub 方法:替換
獲得整個匹配的子串時,可直接使用 group() 或 group(0)
findall 全匹配,返回列表
finditer 方法的行為跟 findall 的行為類似,也是搜尋整個字串,獲得所有匹配的結果。但它返回一個順序訪問每一個匹配結果(Match 物件)的迭代器。
sub 方法用於替換
print p.sub(r'\2 \1', s) # 引用分組
匹配文字中的漢字,有一點需要注意的是,中文的 unicode 編碼範圍 主要在 [u4e00-u9fa5]
注意:貪婪模式(多)與非貪婪模式(少)
- Python裡數量詞預設是貪婪的。
預設是貪婪模式;在量詞後面直接加上一個問號?就是非貪婪模式。
解碼
gbk_html = html.decode('gbk').encode('utf-8')
values = ",".join(map(str, value_list)) #列表轉字串
.*?點代表的是任意字元。* 代表的是取 0 至 無限長度問號代表的是非貪婪模式。三個連結在一起是取儘量少的任意字元
實戰1 使用正則表示式的爬蟲
這個案例能學到很多,好好學,思考
正則用的不好,處理HTML文件很累,有沒有其他的方法?
有!那就是XPath,我們可以先將 HTML檔案 轉換成 XML文件,然後用 XPath 查詢 HTML 節點或元素。
2、XML
父,子,同胞,先輩,後代最常用的路徑表示式:
表示式 | 描述 |
---|---|
nodename | 選取此節點的所有子節點。 |
/ | 從根節點選取。 |
// | 從匹配選擇的當前節點選擇文件中的節點,而不考慮它們的位置。 |
. | 選取當前節點。 |
.. | 選取當前節點的父節點。 |
@ | 選取屬性。 |
選取分主語謂語
lxml 可以自動修正 html 程式碼,例子裡不僅補全了 li 標籤,還添加了 body,html 標籤。
選取類似css選擇器,比較多,不復雜
init函式可以放好多預設值
def __init__(self):
self.tiebaname=raw_input('請輸入要訪問的貼吧:')
self.beginPage = int(raw_input("請輸入起始頁:"))
self.endPage = int(raw_input("請輸入終止頁:"))
self.url='http://tieba.baidu.com/f'
self.ua_header={"User-Agent" : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1 Trident/5.0;"}
實戰2 使用XPath的爬蟲
學會儲存圖片,檢測資料夾是否存在,否則建立新資料夾,使用init函式
3、CSS 選擇器:BeautifulSoup4
抓取工具 | 速度 | 使用難度 | 安裝難度 |
---|---|---|---|
正則 | 最快 | 困難 | 無(內建) |
BeautifulSoup | 慢 | 最簡單 | 簡單 |
lxml | 快 | 簡單 | 一般 |
物件種類
Beautiful Soup將複雜HTML文件轉換成一個複雜的樹形結構,每個節點都是Python物件,所有物件可以歸納為4種:
- Tag 通俗點講就是 HTML 中的一個個標籤
- NavigableString
- BeautifulSoup
- Comment
1. Tag
#建立 Beautiful Soup 物件
soup = BeautifulSoup(html)
print soup.title
# <title>The Dormouse's story</title>
print soup.head
# <head><title>The Dormouse's story</title></head>
print soup.a
# <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
print soup.p
# <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
print type(soup.p)
# <class 'bs4.element.Tag'>
Tag,它有兩個重要的屬性,是 name 和 attrs
print soup.p.attrs
# {'class': ['title'], 'name': 'dromouse'}
# 在這裡,我們把 p 標籤的所有屬性列印輸出了出來,得到的型別是一個字典。
print soup.p['class'] # soup.p.get('class')
# ['title'] #還可以利用get方法,傳入屬性的名稱,二者是等價的
soup.p['class'] = "newClass"
print soup.p # 可以對這些屬性和內容等等進行修改
# <p class="newClass" name="dromouse"><b>The Dormouse's story</b></p>
del soup.p['class'] # 還可以對這個屬性進行刪除
print soup.p
# <p name="dromouse"><b>The Dormouse's story</b></p>
2. NavigableString
既然我們已經得到了標籤的內容,那麼問題來了,我們要想獲取標籤內部的文字怎麼辦呢?很簡單,用 .string 即可,例如
print soup.p.string
# The Dormouse's story
print type(soup.p.string)
# In [13]: <class 'bs4.element.NavigableString'>
3. BeautifulSoup
BeautifulSoup 物件表示的是一個文件的內容。大部分時候,可以把它當作 Tag 物件,是一個特殊的 Tag,我們可以分別獲取它的型別,名稱,以及屬性來感受一下
print type(soup.name)
# <type 'unicode'>
print soup.name
# [document]
print soup.attrs # 文件本身的屬性為空
# {}
4. Comment
Comment 物件是一個特殊型別的 NavigableString 物件,其輸出的內容不包括註釋符號。
print soup.a
# <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
遍歷文件樹
jquery選擇器類似
搜尋文件樹
1.find_all(name, attrs, recursive, text, **kwargs)
name可以傳正則 如:
import re
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
# body
# b
CSS選擇器 (超級好用哦)
這就是另一種與 find_all 方法有異曲同工之妙的查詢方法.
寫 CSS 時,標籤名不加任何修飾,類名前加
.
,id名前加#
在這裡我們也可以利用類似的方法來篩選元素,用到的方法是
soup.select()
print soup.select('b')
select 方法返回的結果都是列表形式,可以遍歷形式輸出,然後用 get_text() 方法來獲取它的內容。實戰3 使用BeautifuSoup4的爬蟲
學會儲存為json格式,哈哈
4、資料提取之JSON與JsonPATH
JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式,它使得人們很容易的進行閱讀和編寫。同時也方便了機器進行解析和生成。適用於進行資料互動的場景,比如網站前臺與後臺之間的資料互動。
JSON和XML的比較可謂不相上下。
JSON
json簡單說就是javascript中的物件和陣列,所以這兩種結構就是物件和陣列兩種結構,通過這兩種結構可以表示各種複雜的結構
json模組提供了四個功能:
物件:物件在js中表示為
{ }
括起來的內容,資料結構為{ key:value, key:value, ... }
的鍵值對的結構,在面向物件的語言中,key為物件的屬性,value為對應的屬性值,所以很容易理解,取值方法為 物件.key 獲取屬性值,這個屬性值的型別可以是數字、字串、陣列、物件這幾種。陣列:陣列在js中是中括號
[ ]
括起來的內容,資料結構為["Python", "javascript", "C++", ...]
,取值方式和所有語言中一樣,使用索引獲取,欄位值的型別可以是 數字、字串、陣列、物件幾種。
dumps
、dump
、loads
、load
,用於字串 和 python資料型別間進行轉換。loads 把Json格式字串解碼轉換成Python物件
strList = '[1, 2, 3, 4]
strDict = '{"city": "北京", "name": "大貓"}'
json.loads(strList)
# [1, 2, 3, 4]
dumps python型別轉化為json字串,返回一個str物件 把一個Python物件編碼轉換成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]'
dump Python內建型別序列化為json物件後寫入檔案
listStr = [{"city": "北京"}, {"name": "大劉"}]
json.dump(listStr, open("listStr.json","w"), ensure_ascii=False)
load 讀取檔案中json形式的字串元素 轉化成python型別
strList = json.load(open("listStr.json"))
print strList
# [{u'city': u'\u5317\u4eac'}, {u'name': u'\u5927\u5218'}]
strDict = json.load(open("dictStr.json"))
JsonPath
JsonPath 是一種資訊抽取類庫,是從JSON文件中抽取指定資訊的工具,提供多種語言實現版本,包括:Javascript, Python, PHP 和 Java。
JsonPath 對於 JSON 來說,相當於 XPATH 對於 XML。
超級乾貨python編碼
json.loads() 是把 Json格式字串解碼轉換成Python物件,如果在json.loads的時候出錯,要注意被解碼的Json字元的編碼。
如果傳入的字串的編碼不是UTF-8的話,需要指定字元編碼的引數 encoding
dataDict = json.loads(jsonStrGBK);
字元編碼
##字串編碼轉換
這是中國程式設計師最苦逼的地方,什麼亂碼之類的幾乎都是由漢字引起的。
其實編碼問題很好搞定,只要記住一點:
####任何平臺的任何編碼 都能和 Unicode 互相轉換
UTF-8 與 GBK 互相轉換,那就先把UTF-8轉換成Unicode,再從Unicode轉換成GBK,反之同理。
``` python
# 這是一個 UTF-8 編碼的字串
utf8Str = "你好地球"
# 1. 將 UTF-8 編碼的字串 轉換成 Unicode 編碼
unicodeStr = utf8Str.decode("UTF-8")
# 2. 再將 Unicode 編碼格式字串 轉換成 GBK 編碼
gbkData = unicodeStr.encode("GBK")
# 1. 再將 GBK 編碼格式字串 轉化成 Unicode
unicodeStr = gbkData.decode("gbk")
# 2. 再將 Unicode 編碼格式字串轉換成 UTF-8
utf8Str = unicodeStr.encode("UTF-8")
decode
的作用是將其他編碼的字串轉換成 Unicode 編碼
encode
的作用是將 Unicode 編碼轉換成其他編碼的字串
一句話:UTF-8是對Unicode字符集進行編碼的一種編碼方式
實戰4 糗事百科
爬取糗事百科段子,假設頁面的URL是 http://www.qiushibaike.com/8hr/page/1使用requests獲取頁面資訊,用XPath / re 做資料提取
獲取每個帖子裡的
使用者頭像連結
、使用者姓名
、段子內容
、點贊次數
和評論次數
儲存到 json 檔案內
使用requests高階 錯誤處理 xpath
經典實戰5 多執行緒糗事百科
多看視訊,看起來有點難,執行緒,佇列Queue(佇列物件)
對於資源,加鎖是個重要的環節。因為python原生的list,dict等,都是not thread safe的。而Queue,是執行緒安全的,因此在滿足使用條件下,建議使用佇列
初始化: class Queue.Queue(maxsize) FIFO 先進先出
包中的常用方法:
Queue.qsize() 返回佇列的大小
Queue.empty() 如果佇列為空,返回True,反之False
Queue.full() 如果佇列滿了,返回True,反之False
Queue.full 與 maxsize 大小對應
Queue.get([block[, timeout]])獲取佇列,timeout等待時間
建立一個“佇列”物件
- import Queue
- myqueue = Queue.Queue(maxsize = 10)
將一個值放入佇列中
- myqueue.put(10)
將一個值從佇列中取出
- myqueue.get()