Hello Python!用 Python 寫一個抓取 CSDN 博客文章的簡單爬蟲

網絡上一提到 Python,總會有一些不知道是黑仍是粉的人大喊着:Python 是世界上最好的語言。最近利用業餘時間體驗了下 Python 語言,並寫了個爬蟲爬取我 csdn 上關注的幾個大神的博客,而後利用leancloud一站式後端雲服務器存儲數據,再寫了一個 android app 展現數據,也算小試了一下這門語言,給個人感受就是,像 Python 這類弱類型的動態語言相比於 Java 來講,開發者不須要分太多心去考慮編程問題,可以把精力集中於業務上,思考邏輯的實現。下面分享一下我這次寫爬蟲的一下小經驗,拋磚引玉。javascript

開發環境的搭建

登陸 Python 官網下載客戶端,Python 如今分爲 Python3 和 Python2, 即對應的官網上的版本爲3.5和2.7,兩者的異同有興趣能夠搜索一下,就個人瞭解,2和3的語法會有不一樣,並且有的庫支持2不支持3,有的支持3不支持2等等;又好比urllib2庫(一個用來獲取URLs的模塊)在 Python2 上引用要 import urllib2, 而在 Python3 裏就變成import urllib.request。等等。糾結使用哪一個版本沒有意義,代碼是爲邏輯服務的,不管2或3很明顯均可以知足咱們這些初學者的需求。這裏推薦一下廖學峯老師的 Python 教程。很高質量的教程,2和3都有,嫌看視頻學得慢的朋友能夠試試。css

~~可是這裏有一個坑要提醒一下:若是你也和我同樣想要使用leancloud作後端服務器,那得使用 Python2,無他,由於人家文檔裏寫着暫不支持 Python3。╮(╯_╰)╭~~(6.28 更正:leancloud 現已支持 Python3)html

搭建環境的一些小坑:error2502/2503

下載客戶端後,若是你點擊安裝後一切正常,那你能夠忽略此步。若是出現安裝失敗 error2502/2503,解決辦法以下:html5

  1. 打開命令提示符(管理員),若是你是win8:按win鍵進入桌面模式,左下角右鍵打開命令提示符(管理員)
  2. 輸入 msiexec /package "你安裝程序包的路徑"(例如:F:\python)

安裝成功後配置環境變量(個人電腦-右鍵 屬性-高級系統設置-環境變量)添加安裝的目錄(C:\Python27)到path。以後打開命令行輸入python,若是出現以下圖三個小箭頭則說明 Python 解釋器已經安裝成功了。java

Python安裝成功

安裝pip和beautifulsoup:

pip,你們能夠理解成至關於android studio的gradle,能夠一鍵配置開源庫到項目中(後續配置leancloud服務器也能夠很方便的導入他們的模塊)。beautifulsoup則是一個HTML解析器,使用它解析html標籤方便又簡單。python

  1. 首先下載pip,下載 pip-8.1.2.tar.gz (md5, pgp)
  2. 解壓後,打開cmd命令行,切換盤符,再cd 進入解壓的目錄,例如: cd D:\pip-8.1.2
  3. 命令行裏輸入 python setup.py install ,看到finished processing等字樣即安裝成功
  4. 配置環境變量到path: C:\Python27\Scripts;
  5. cmd 運行 pip install beautifulsoup4 ,看到successfully installed即安裝成功

安裝模塊成功

另外再推薦一款編輯器:pycharm,JetBrains出品你懂的,InteliJ系列風格,使用這款編輯器你會感受像是在使用android studio同樣,至少設置個字體大小啥的都不陌生。jquery

萬事俱備,Let's begin!android

初識爬蟲

由於我也纔剛接觸 Python,因此有一些代碼可能很無腦且未通過優化,僅僅只爲實現需求,so~下面就開始分享我寫的一些 Python 代碼,以及寫爬蟲時遇到的一些小坑web

假裝瀏覽器

CSDN禁止爬蟲,因此要爬取以前就要把爬蟲假裝成瀏覽器,在訪問以前增長一個header:編程

user_agents = [ 
    'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11',
    'Opera/9.25 (Windows NT 5.1; U; en)',
    'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
    'Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.5 (like Gecko) (Kubuntu)',
    'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12',
    'Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9',
    "Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.7 (KHTML, like Gecko) Ubuntu/11.04 Chromium/16.0.912.77 Chrome/16.0.912.77 Safari/535.7",
    "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:10.0) Gecko/20100101 Firefox/10.0 ",
]
agent = random.choice(user_agents) #每次隨機抽取一個假裝的客戶端瀏覽器版本號
req = urllib2.Request(self.url) #將要請求的地址映射成request對象,而後能夠對其添加HTTP頭
req.add_header('User-Agent', agent)
req.add_header('Host', 'blog.csdn.net')
req.add_header('Accept', '*/*')
req.add_header('Referer', 'http://blog.csdn.net/mangoer_ys?viewmode=list')
req.add_header('GET', url)
html = urllib2.urlopen(req) #將request對象傳入urlopen方法,返回一個response對象
page = html.read().decode('utf-8') #調用read方法就能夠得到html網頁的信息了,主要還要對其轉碼爲utf-8

這裏就已經爬取到網頁內容了(page),後面只要經過正則來解析你須要的數據,簡單的爬蟲其實就已經完成了。

如今來整理一下,咱們到底須要一些什麼數據?個人目的是爬取一個,甚至幾個博主的所有博客,而後在手機上展現。那麼就須要:

  • 先訪問給定的網址(博主的博客首頁),並獲取一篇博客的連接地址,而後讓爬蟲去訪問該地址
  • 得到這篇博文的標題,做者,發表時間、文章內容。這些是最基礎的,也是必要的展現內容
  • 得到這篇博文的id,做者的id,用來作後端存儲數據的惟一標識
  • 得到這篇博文底部的上一篇/下一篇博文按鈕所連接的地址,並讓爬蟲訪問改地址
  • 循環往復,直到不存在上一篇/下一篇博文

建立一個類來執行第一個業務:
要注意的是: Python 的規定方法定義必須有額外的參數self指代其自己,相似java的this。

class Get_First_Url: #用於獲取博客首頁第一篇博文的地址的類
    def __init__(self, url2): #類構造器,這裏咱們還傳入一個url,即博客首頁的地址
        self.url = url2 #將參數賦值給類,python裏能夠任意添加成員變量而不用提早聲明,要用的時候直接調用self.xxx
        '''
        假裝瀏覽器
        '''
        self.page = page #獲取的網頁信息
        self.beginurl = self.getFirstUrl() #下面咱們會定義一個方法來解析網頁並保存一篇的地址

解析html標籤

上面得到的 page 包含了全部的網頁裏的 html 標籤,咱們如今就要解析標籤,得到信息,舉個例子,在個人博客主頁裏右鍵-查看源代碼,能夠看到整個網址包含的全部html標籤,如何從中找到本身想要的信息是哪一個標籤呢?

審查元素

以獲取第一篇博客的連接地址爲例,右鍵標題,審查元素,就能夠看到該連接的html標籤了

標籤

<span class="link_title">
    <a href="/yazhi1992/article/details/51497576">
        eclipse再見,android studio 新手入門教程(三)Github(.ignore忽略規則)的使用            
    </a>
</span>

很容易看出,博客地址就是 csdn 網址拼接span標籤內的a標籤的key爲href對應的value值。爲了獲得這個值,就要使用 breautifulsoup 解析,咱們定義一個方法:

def getFirstUrl(self):
    bs = BeautifulSoup(self.page) #建立breautifulsoup對象
    html_content_list = bs.find('span', class_='link_title') #得到key爲class,value爲link——title的span標籤,由於class與python語法的關鍵字衝突,因此要使用 class_ 代替
    if (html_content_list == None): #若是未找到該標籤則返回'nourl'
            return "no url"
    try: #異常捕獲
        return 'http://blog.csdn.net' + html_content_list.a['href']
    except Exception, e:
        return "nourl"

因此到這裏,咱們就已經能夠獲得咱們所須要的第一個數據了:

first_spider = Get_First_Url(now_url) 
begin_url = first_spider.beginurl

獲取其餘數據方法相似,值得一提的是另外一種標籤的解析,須要的數據是標籤內部的文字:

<div class="article_r">
    <span class="link_postdate">I want this</span>
</div>

想要得到標籤的內容

bs = BeautifulSoup(self.page) #建立breautifulsoup對象       
html_content_list = bs.find('span', class_='link_postdate')
print html_content_list.string

我還遇到過想要獲取時間2015-10-10 16:24這個值,可是執行上述代碼會報錯,提說說soup沒有string這個值,那就須要對其作個轉變爲字符串的操做

print str(html_content_list.string)

更多breautifulsoup的用法能夠參考Python爬蟲利器二之Beautiful Soup的用法

編碼問題:python Non-ASCII character '\xe5' in file

若是你運行程序後報這個錯,解決辦法是在文件頭添加:

#coding=utf-8
import sys
default_encoding = 'utf-8'
if sys.getdefaultencoding() != default_encoding:
    reload(sys)
    sys.setdefaultencoding(default_encoding)

關於 Python 的一些注意點:

talk is cheap, show you the code.

切割字符串

str = 'this is test'  
print str[:4]  #輸出結果  this
print str[3:]  #輸出結果  s is test
print str[1:4]  #輸出結果  his

不用多說,冒號「 : 」表明首或尾,和java同樣的包左不包右。若是首尾都是數字,中間用冒號分割。

關於數組

list = []
print list[-2] #數組倒數第二個的值

關於全局變量

直接在外部定義全局變量,可是使用時須要用globla關鍵字表示

TEST = 'this is global variable'

class ...
    def...
        global TEST  #使用關鍵字標識這個TEST是全局變量
        print TEST   #使用該變量

關於導包

IDE好像不能自動導包(我也沒認真去翻setting)導包的話直接在文件頭import相應的包,例如

from bs4 import BeautifulSoup  #導breatifulsoup的包
import urllib2  
import random 
...等等

關於布爾類型True、False

Python 的布爾類型是首字母大寫的(或者IDE能夠設置忽略大小寫聯想,我沒有去仔細翻)。(╯‵□′)╯︵┻━┻

其餘

if(list==null||list.size == 0) {  //java
    ...
} else {
    ...
}

if (list == None or len(list) == 0):  #python
    ...
else:  
    ...

由於我是爬取正文的html標籤,而後在android端上使用webview展現,可是有個問題是webview裏會顯示電腦端的效果,字很小。查看手機端網頁源代碼後,發如今html標籤頭添加如下代碼,就能夠適配移動端瀏覽器:

<head>
   <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-status-bar-style" content="yes">
    <script src="http://csdnimg.cn/public/common/libs/jquery/jquery-1.9.1.min.js" type="text/javascript"></script>
    <!--link( rel="stylesheet" href="http://c.csdnimg.cn/public/common/toolbar/css/index.css" )-->
    <link rel="stylesheet" href="http://csdnimg.cn/public/common/libs/bootstrap/css/bootstrap.css">
    <link rel="stylesheet" href="http://csdnimg.cn/public/static/css/avatar.css">
    <link rel="stylesheet" href="/static/css/common.css">
    <!-- [if IE 7]-->
    <!--link( rel="stylesheet" href="assets/css/font-awesome-ie7.min.css" )-->
    <!-- [endif]-->
    <link rel="stylesheet" href="/static/css/main.css">
    <!-- [if lt IE 9]-->
    <script src="/static/js/libs/html5shiv.min.js"></script>
    <!-- [endif]-->
    <title></title>
    <script type="text/javascript" src="/static/js/apps/blog_mobile.js"></script>
</head>

另外,關於webview網頁裏圖片自適應,4.4之前只須要:

WebSettings webSettings= contentWeb.getSettings();
webSettings.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);

可是在Android 4.4系統上 Google已經將系統默認的Webkit內核替換成本身的開源項目chromium,致使的一個問題就是上述代碼失效了,解決方法請參考Android 中 WebView 與 js 簡單交互實現圖文混排效果,解決圖片自適應屏幕與查看大圖問題,親測有效。

webview圖片自適應

Python 爬蟲源碼下載,請替換本身的leancloud應用的id和key,具體如何在爬蟲裏上傳數據,以及在app裏如何讀取數據,請閱讀leancloud官方開發文檔

Stay hungry, Stay foolish。下篇博客見。

相關文章
相關標籤/搜索