1. 程式人生 > >黑馬python2.7的爬蟲2-非結構化資料與結構化資料提取

黑馬python2.7的爬蟲2-非結構化資料與結構化資料提取

非結構化資料與結構化資料提取

抓取的是某個網站或者某個應用的內容,提取有用的價值。內容一般分為兩部分,非結構化的資料 和 結構化的資料。

  • 非結構化資料:先有資料,再有結構,
  • 結構化資料:先有結構、再有資料
  • 不同型別的資料,我們需要採用不同的方式來處理。

1、非結構化的資料處理

文字、電話號碼、郵箱地址
  • 正則表示式
HTML 檔案
  • 正則表示式
  • XPath
  • CSS選擇器

2、結構化的資料處理

JSON 檔案
  • JSON Path
  • 轉化成Python型別進行操作(json類)
XML 檔案
  • 轉化成Python型別(xmltodict)
  • XPath
  • CSS選擇器
  • 正則表示式

爬蟲一共就四個主要步驟:

  1. 明確目標 (要知道你準備在哪個範圍或者網站去搜索)
  2. 爬 (將所有的網站的內容全部爬下來)
  3. 取 (去掉對我們沒用處的資料)
  4. 處理資料(按照我們想要的方式儲存和使用)

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]

注意:貪婪模式(多)與非貪婪模式(少)

  1. 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中的物件和陣列,所以這兩種結構就是物件和陣列兩種結構,通過這兩種結構可以表示各種複雜的結構

  1. 物件:物件在js中表示為{ }括起來的內容,資料結構為 { key:value, key:value, ... }鍵值對的結構,在面向物件的語言中,key為物件的屬性,value為對應的屬性值,所以很容易理解,取值方法為 物件.key 獲取屬性值,這個屬性值的型別可以是數字、字串、陣列、物件這幾種。

  2. 陣列:陣列在js中是中括號[ ]括起來的內容,資料結構為 ["Python", "javascript", "C++", ...],取值方式和所有語言中一樣,使用索引獲取,欄位值的型別可以是 數字、字串、陣列、物件幾種。

json模組提供了四個功能:dumpsdumploadsload,用於字串 和 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
  1. 使用requests獲取頁面資訊,用XPath / re 做資料提取

  2. 獲取每個帖子裡的使用者頭像連結使用者姓名段子內容點贊次數評論次數

  3. 儲存到 json 檔案內

使用requests高階  錯誤處理 xpath

經典實戰5 多執行緒糗事百科

多看視訊,看起來有點難,執行緒,佇列

Queue(佇列物件)

對於資源,加鎖是個重要的環節。因為python原生的list,dict等,都是not thread safe的。而Queue,是執行緒安全的,因此在滿足使用條件下,建議使用佇列

  1. 初始化: class Queue.Queue(maxsize) FIFO 先進先出

  2. 包中的常用方法:

    • Queue.qsize() 返回佇列的大小

    • Queue.empty() 如果佇列為空,返回True,反之False

    • Queue.full() 如果佇列滿了,返回True,反之False

    • Queue.full 與 maxsize 大小對應

    • Queue.get([block[, timeout]])獲取佇列,timeout等待時間

  3. 建立一個“佇列”物件

    • import Queue
    • myqueue = Queue.Queue(maxsize = 10)
  4. 將一個值放入佇列中

    • myqueue.put(10)
  5. 將一個值從佇列中取出

    • myqueue.get()