學習極客學院多線程爬蟲課程的收穫

昨天開始了極客學院《XPath與多線程爬蟲》課程的學習,主要涉及到XPath和requests的使用,在測試過程當中出現了不少問題,通過不斷摸索以及前輩們的幫助,現將經驗總結以下:
1. Python3下面文本編碼問題
雖然Python3相對於2已經集成了不少編碼方式,使咱們不須要過多去關心和指定編碼,但有時候在文本讀取,寫入的時候仍是須要多當心,在測試過程當中屢次出如今寫入文件時報告錯誤「UnicodeEncodeError: 'ascii' codec can't encode character '\u56de' in position 0: ordinal not in range(128)」,這是因爲咱們在抓取網頁的時候採用的是UTF-8編碼,而存儲時沒有指定編碼,在存儲到文件的過程當中就會報錯。
解決辦法爲:
在讀取文件時加入指定UTF-8編碼的選項html

f = open('content.txt','a',encoding='UTF-8')

另外須要注意的是使用requests獲取到網頁以後一樣要指定編碼正則表達式

html = requests.get(url)
html = re.sub(r'charset=(/w*)', 'charset=UTF-8', html.text)

2. XPath的用法
XPath能夠很方便的解析XML文件的節點和屬性,使用也很簡單,相比於正則表達式來講,XPath的查詢方式更加高效準確,它來自於lxml包內的etree,在使用以前應該聲明編程

from lxml import etree

在使用XPath應該遵循「先抓大,再抓小」的原則,現定位到大的節點,獲取到全部字節點再一層一層往下尋找,直到獲取所須要的信息
例如,咱們想要抓取百度貼吧的網頁每個樓層的信息(包括做者,回帖時間,回帖內容等等),經過Chrome-Inspect element能夠審查代碼,獲得某一個樓層的代碼樓層最外層都有聲明:json

<div class="l_post j_l_post l_post_bright  "

使用XPath先獲取整個樓層的全部節點(Node)多線程

content_field = selector.xpath('//div[@class="l_post j_l_post l_post_bright  "]')

再往下尋找,發現咱們要提取的內容位於app

<div class="d_post_content_main">

這一個節點之內,再繼續往下挖掘:編程語言

content =each.xpath('div[@class="d_post_content_main"]/div/cc/div[@class="d_post_content j_d_post_content  clearfix"]/text()')

這樣一步步獲得想要的內容ide

3.JSON格式
網頁中不少內容使用JSON來傳輸,咱們要把內容還原出來須要使用json模塊函數式編程

import json
reply_info = json.loads(each.xpath('@data-field')[0].replace('&quot',''))

4.Python中的多線程
多線程能夠很大幅度提升軟件的處理速度,能夠充分利用計算機性能,不一樣的核處理不一樣的任務,並行執行,提升處理速度,使用方法以下:函數

from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(8)
results = pool.map(spider,page)
pool.close()
pool.join()

map 這一小巧精緻的函數是簡捷實現 Python 程序並行化的關鍵。map 源於 Lisp 這類函數式編程語言。它能夠經過一個序列實現兩個函數之間的映射。上面的這兩行代碼將 page這一序列中的每一個元素做爲參數傳遞到 spyder 方法中,並將全部結果保存到 results 這一列表中。其結果大體至關於:

results = []
for page in pages: 
    results.append(spyder(page))

上述代碼中調用join以前,先調用close函數,不然會出錯。執行完close後不會有新的進程加入到pool,join函數等待全部子進程結束。

所有代碼:

#-*-coding:utf8-*-
from lxml import etree
from multiprocessing.dummy import Pool as ThreadPool
import requests
import json
import re
import sys

'''從新運行以前請刪除content.txt,由於文件操做使用追加方式,會致使內容太多。'''

def towrite(contentdict):
    #f=open("content.txt",'wb')
    f.writelines(u'回帖時間:' + str(contentdict['topic_reply_time']) + '\n')
    f.writelines(u'回帖內容:' + str(contentdict['topic_reply_content']) + '\n')
    f.writelines(u'回帖人:' + contentdict['user_name'] + '\n\n')
    #f.close()

def spider(url):
    html = requests.get(url)
    #print(html.text)
    html = re.sub(r'charset=(/w*)', 'charset=UTF-8', html.text)
    selector = etree.HTML(html)
    # print(selector)
    #content_field = selector.xpath('//div[starts-with(@class,"l_post l_post_bright")]')p_content p_content_nameplate
    #content_field = selector.xpath('//*[@id="j_p_postlist"]')
    content_field = selector.xpath('//div[@class="l_post j_l_post l_post_bright  "]')
    item = {}
    for each in content_field:
        reply_info = json.loads(each.xpath('@data-field')[0].replace('&quot',''))
        author = reply_info['author']['user_name']
        # content1 = each.xpath('//div[@class="d_post_content_main"]')
        content = each.xpath('div[@class="d_post_content_main"]/div/cc/div[@class="d_post_content j_d_post_content  clearfix"]/text()')
        reply_time = reply_info['content']['date']
        print("content:{0}".format(content))
        print("Reply_time:{0}".format(reply_time))
        print("Author:{0}".format(author))
        item['user_name'] = author
        item['topic_reply_content'] = content
        item['topic_reply_time'] = reply_time
        towrite(item)

if __name__ == '__main__':
    pool = ThreadPool(8)
    f = open('content.txt','a',encoding='UTF-8')
    # f = open('content.txt','a')
    page = []
    for i in range(1,21):
        newpage = 'http://tieba.baidu.com/p/3522395718?pn=' + str(i)
        page.append(newpage)

    results = pool.map(spider,page)
    pool.close()
    pool.join()
    f.close()

結果以下:

回帖時間:2015-01-11 16:52
回帖內容:['            6和plus糾結買哪款。還有 買完新機可讓他上色嗎']
回帖人:鬥已轉0

回帖時間:2015-01-11 16:53
回帖內容:['            我如今是以貼吧高級會員的身份幫你頂貼,請注意你的態度']
回帖人:暑假幹啥

回帖時間:2015-01-11 16:57
回帖內容:['            我去']
回帖人:qw518287200

回帖時間:2015-01-11 16:57
回帖內容:['            能教我怎麼看序列號或imei號麼,大神\uf618']
回帖人:花顏誘朕醉

須要注意的是,極客學院附帶資料的源代碼是沒法使用的,以上說到的幾點就是我在調試過程當中淌過的坑,要注意使用Chrome對要抓取的網頁進行細心分析,修改xpath參數並不斷試驗。

+++++++明日計劃++++++++++++++++加入計時功能,測試單線程與多線程的性能差異嘗試抓取網頁中的圖片並保存

相關文章
相關標籤/搜索