Python爬蟲初學(一)—— 爬取段子

最近開始學Python的爬蟲,是在這個博客跟著學習的,該博主用的是Python 2.7版本,而我使用的是3.5版本,很多不兼容的地方,不過沒關系,自己改改就好了。

我們想針對網站的內容進行篩選,只獲取自己感興趣的部分。比如你想在XX網站把小黃圖篩選出來,打包帶走。這里只做簡單的實現,以百思不得姐上的段子(純文本)為例。我們想要實現如下功能:

  • 批量下載若干頁段子到本地文件中
  • 按下任意一鍵,開始閱讀下一條段子

1. 獲取網頁代碼

導入urllib的相關庫,Python 3中應該這樣寫:

import urllib.request
import urllib.parse
import re

re庫是正則表達式(Regular Expression),后面作匹配時會用到。

百思不得姐的段子頁面url ='http://www.budejie.com/text/1',這里末尾數字1代表此為第一頁。通過以下代碼就能返回網頁內容。

    req = urllib.request.Request(url)
    # 添加headers 使之看起來像瀏覽器在訪問
    req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 '
                                 '(KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36')
    response = urllib.request.urlopen(req)
    # 得到網頁內容,注意必須使用decode()解碼
    html = response.read().decode('utf-8')

print(html)的話,就是如下所示的內容:

這能看?段子呢?我們想要的段子呢?!

哦對了headers這樣查看。

按F12,然后...看圖吧

2. 正則匹配提取段子

要想篩選符合普通人閱讀的內容(如果還帶著html標簽那還咋讀是不),成功提取出段子,為此我們需要一些既定的模式去和網頁全部內容進行匹配,將模式下匹配成功的對象返回。我們使用強大的正則表達式進行匹配(Regular Expression),相關語法可以看這里

僅僅針對本例中的網頁內容,先看看我們需要的段子對應了網頁中的什么內容。

可以看到段子被<div class="j-r-list-c-desc">(我們要的內容)</div>這樣的標簽所包圍,只需要指定相應規則提取出來即可!上圖可以看出段子正文前后是有很多空格的,需要匹配進去。

pattern = re.compile(r'<div class="j-r-list-c-desc">\s+(.*)\s+</div>')
result = re.findall(pattern, html)

通過re庫的compile函數制定規則。

  • \s+可以匹配一個或更多的空格
  • .匹配除開換行符\n外的所有字符。

現在我們得到了匹配后的結果,來看下。

Bingo!提取出來了不是?!

可是我們發現里面還有些討厭的<br />。沒關系,寫幾行代碼的事。這里就不再展示去掉后的內容,自行腦補哈哈。

    for each in content:
        # 如果某個段子里有<br />
        if '<br />' in each:
            # 替換成換行符并輸出
            new_each = re.sub(r'<br />', '\n', each)
            print(new_each)
        # 沒有就照常輸出
        else:
            print(each)

這里content由get_content方法返回,表示所有獲取到的段子列表。get_content方法下面會給出實現。

至此,我們成功得到我們想看的段子了!如果想要下載到本地呢?

3. 下載段子到本地

通過定義一個save()函數即可,num參數用戶自定,想下載最近100頁的內容都沒問題!里面還有些變量沒有提到,最后會給出源代碼。

# num是指定網頁頁數
def save(num):
    # 寫方式打開一個文本,把獲取的段子列表存放進去
    with open('a.txt', 'w', encoding='utf-8') as f:
        text = get_content(num)
        # 和上面去掉<br />類似
        for each in text:
            if '<br />' in each:
                new_each = re.sub(r'<br />', '\n', each)
                f.write(new_each)
            else:
                f.write(str(each) + '\n')

下載到本地文檔后如下圖所示

4. 逐條讀取段子

段子太多,琳瑯滿目。可我們只希望一條條閱讀。通過按下鍵盤任意鍵可以切換到下一條,直到讀取到最后一條程序才結束,或者通過設置一個退出鍵隨時退出程序,比如設定q鍵退出。這里把全部代碼給出。

import urllib.request
import urllib.parse
import re

pattern = re.compile(r'<div class="j-r-list-c-desc">\s+(.*)\s+</div>')

# 返回指定網頁的內容
def open_url(url):
    req = urllib.request.Request(url)
    req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 '
                                 '(KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36')
    response = urllib.request.urlopen(req)
    html = response.read().decode('utf-8')
    return html

# num為用戶自定,返回的是所有頁的段子列表
def get_content(num):
    # 存放段子的列表
    text_list = []
    for page in range(1, int(num)):
        address = 'http://www.budejie.com/text/' + str(page)
        html = open_url(address)
        result = re.findall(pattern, html)
        # 每一頁的result都是一個列表,將里面的內容加入到text_list
        for each in result:
            text_list.append(each)
    return text_list


# num是指定網頁頁數
def save(num):
    # 寫方式打開一個文本,把獲取的段子列表存放進去
    with open('a.txt', 'w', encoding='utf-8') as f:
        text = get_content(num)
        # 和上面去掉<br />類似
        for each in text:
            if '<br />' in each:
                new_each = re.sub(r'<br />', '\n', each)
                f.write(new_each)
            else:
                f.write(str(each) + '\n')
                
                
if __name__ == '__main__':
    print('閱讀過程中按q隨時退出')
    number = int(input('想讀幾頁的內容: '))
    content = get_content(number + 1)
    for each in content:
        if '<br />' in each:
            new_each = re.sub(r'<br />', '\n', each)
            print(new_each)
        else:
            print(each)
        # 用戶輸入
        user_input = input()
        # 不區分大小寫的q,輸入則退出
        if user_input == 'q' or user_input == 'Q':
            break

演示一下,效果是這樣的。


雖然功能很雞肋,不過作為初學我還是很滿意了,有興趣才能深入下去嘛!爬蟲可不僅僅如此而已,以后會學習更加高級的功能。


by @sunhaiyu

2016.8.15

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,327評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,996評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,316評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,406評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,128評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,524評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,576評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,759評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,310評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,065評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,249評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,821評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,479評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,909評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,140評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,984評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,228評論 2 375

推薦閱讀更多精彩內容