記念個人第一個完整的小說爬蟲

記念個人第一個爬蟲程序,一共寫了三個白天,其中有兩個上午沒有看,中途遇到了各類奇怪的問題,伴隨着他們的解決,對於一些基本的操做也弄清楚了。果真,對於這些東西的最號的學習方式,就是在使用中學習,經過解決問題的方式來搞定這些知識。按需索取,才能更有針對性。html

大致記錄下整個過程。python


準備構思

出於對於python的熱愛,想要嘗試一些練手的項目,可是不管是看書,仍是直接嘗試別人的項目,到最後都會淪爲不停地複製粘貼...最實際的就是本身來上手親自寫代碼。思路都是同樣的,可是具體的實現還得靠本身。正則表達式

之前的複製粘貼給個人幫助也就是告訴了我大體的流程。express

肯定目標網址

目標網址是關鍵。我夢想中的爬蟲是那種偏向於更智能的,直接給他一個想要獲取的關鍵詞,一步步的流程直接本身完成,能夠本身給定範圍,也能夠直接爬取整個互聯網或者更實際的就是整個百度上的內容,可是,目前就我而言,見到的爬蟲,都是給定目標網址,經過目標頁面上的內容進一步執行規定的操做,因此如今來看,咱們在寫爬蟲以前,須要肯定一個基準頁面,這個是須要咱們事先制定的。在考慮咱們須要程序完成怎樣的功能,獲取頁面文本仍是相關連接內容仍是其餘的目的。編程

我這個程序想要獲取的是《劍來》小說,把各個章節的內容爬去下載存儲到文件裏。瀏覽器

編程只是實現目的的工具。安全

因此重點是分析咱們的需求。python爬蟲

獲取小說目錄頁面是基本。這裏有各個章節的連接,標題等等內容。這是咱們須要的。socket

有了各個章節的連接,就須要進入其中得到各個章節的內容。工具

因此,咱們須要得到頁面內容,須要從中得到目標內容。

因此使用 urllib.requestre 庫。

前者用來得到網頁內容,後者得到目標信息。

headers

直接使用urllib.requesturlopen()read()方法是會報相似如下的錯誤(這裏是網上查找過來的,都是相似的):

raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
HTTPError: HTTP Error 403: Forbidden

出現urllib2.HTTPError: HTTP Error 403: Forbidden錯誤是因爲網站禁止爬蟲,能夠在請求加上頭信息,假裝成瀏覽器。

headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0'}
request = url_req.Request(url, headers=headers)
response = url_req.urlopen(request, data=None, timeout=3)
html = response.read().decode('GBK')

注意:這裏存在兩個容易出問題的地方。

  • 編碼:編碼問題是使用爬蟲中有時候會很頭痛的問題,因爲網頁源代碼編碼格式不明確,因此這裏嘗試了許久。

使用chardet庫的detect()方法能夠檢測字節字符串的編碼。因此直接檢測這裏的html(先不要解碼)。輸出的是GB2312,可是在後面頁面的爬取中,會出現提示有的字符的編碼異常,因此這裏採起了比其範圍更廣的中文字符集GBK,解決了這個問題。

  • 設置超時範圍:因爲頻繁的獲取網頁內容,目標網站有時候會出現沒有響應的問題。

(這個問題能夠見我在CSDN上的提問:關於python爬蟲程序中途中止的問題

因而我採起了捕獲 urlopen()socket.timeout異常,並在出現異常的時候再循環訪問,直到得到目標頁面。

得到目標內容

這裏使用的是正則表達式。re模塊。這裏的使用並不複雜。

首先須要一個模式字符串。以re.I指定忽略大小寫,編譯後的對象擁有自己匹配的方法,這裏使用的是findall(),返回一個全部結果組成的列表。能夠及時返回輸出其內容,進而選擇合適的部分進行處理。

python 正則表達式

經過查看相關的符號,這裏使用(.+?)來實現匹配非貪婪模式(儘可能少的)下任意無限字符,對之使用(),進而匹配括號內的模式。

文件寫入

使用with open() as file:,進而能夠處理文件。而且能夠自動執行打開和關閉文件,更爲便捷安全。

with open(findall_title[0] + '.txt', 'w+', encoding='utf-8') as open_file:
  • 這裏也要注意編碼的問題,指定utf-8。會避免一些問題。
  • 這裏使用w+模式,追加寫文件。

完整代碼

# -*- coding: utf-8 -*-
"""
Created on Fri Aug 11 16:31:42 2017
@author: lart
"""

import urllib.request as url_req
import re, socket, time


def r_o_html(url):
    print('r_o_html begin')

    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0'}

    request = url_req.Request(url, headers=headers)

    NET_STATUS = False
    while not NET_STATUS:
        try:
            response = url_req.urlopen(request, data=None, timeout=3)
            html = response.read().decode('GBK')
            print('NET_STATUS is good')
            print('r_o_html end')
            return html
        except socket.timeout:
            print('NET_STATUS is not good')
            NET_STATUS = False

def re_findall(re_string, operation, html):

    print('re_findall begin')
    pattern = re.compile(re_string, re.I)

    if operation == 'findall':
        result = pattern.findall(html)
    else:
        print('this operation is invalid')
        exit(-1)

    print('re_findall end')
    return result


if __name__ == '__main__':
    url_base = 'http://www.7kankan.la/book/1/'

    html = r_o_html(url_base)

    findall_title = re_findall(r'<title>(.+?)</title>', 'findall', html)

    findall_chapter = re_findall(r'<dd class="col-md-3"><a href=[\',"](.+?)[\',"] title=[\',"](.+?)[\',"]>', 'findall', html)

    with open(findall_title[0] + '.txt', 'w+', encoding='utf-8') as open_file:
        print('article文件打開', findall_chapter)
        for i in range(len(findall_chapter)):
            print('第' + str(i) + '章')

            open_file.write('\n\n\t' + findall_chapter[i][1] + '\n --------------------------------------------------------------------- \n')

            url_chapter = url_base + findall_chapter[i][0]

            html_chapter = r_o_html(url_chapter)

            findall_article = re_findall(r'&nbsp;&nbsp;&nbsp;&nbsp;(.+?)<br />', 'findall', html_chapter)

            findall_article_next = findall_chapter[i][0].replace('.html', '_2.html')

            url_nextchapter = url_base + findall_article_next

            html_nextchapter = r_o_html(url_nextchapter)

            if html_nextchapter:
                findall_article.extend(re_findall(r'&nbsp;&nbsp;&nbsp;&nbsp;(.+?)<br />', 'findall', html_nextchapter))

                for text in findall_article:
                    open_file.write(text + '\n')

            time.sleep(1)

    print('文件寫入完畢')
相關文章
相關標籤/搜索