Python 爬蟲入門實戰

1. 前言

首先自我介紹一下,我是一個作 Java 的開發人員,從今年下半年開始,一直在各大技術博客網站發表本身的一些技術文章,差很少有幾個月了,以前在 cnblog 博客園加了網站統計代碼,看到天天的訪問量逐漸多了起來,國慶正好事情很少,就想着寫一個爬蟲,看下具體閱讀量增長了多少,這也就成了本文的由來。html

2. 技術選型

爬蟲這個功能,我我的理解是什麼語言都能寫的,只要能正常發送 HTTP 請求,將響應回來的靜態頁面模版 HTML 上把咱們所須要的數據提取出來就能夠了,原理很簡單,這個東西固然能夠手動去統計收集,可是網絡平臺畢竟仍是不少的,仍是畫點時間,寫個爬蟲把數據爬取下來,存到數據庫裏,而後寫一個統計報表的 SQL 語句比較方便,後續若是有時間的話,我會寫一個簡單的先後端分離的報表樣例分享出來。node

網上如今 Python 爬蟲的課程很是的火爆,其實我內心也有點小九九,想玩點騷操做,不想用老本行去寫這個爬蟲,固然最後的事實是證實確實用 Python 寫爬蟲要比用 Java 來寫爬蟲要簡單的多。python

3. 環境準備

首先筆者的電腦是 Win10 的,Python 選用的是 3.7.4 ,貌似如今網上 Python3 的爬蟲教程並很少,其中仍是遇到很多的問題,下面也會分享給你們。mysql

開發工具筆者選用的是 VSCode ,在這裏推薦一下微軟這個開源的產品,很是的輕量化,須要什麼插件本身安裝就好,不用的插件一概不要,自主性很是高,若是感受搞不定的朋友能夠選擇 JetBrains 提供的 Pycharm ,分爲社區版和付費版,通常而言,咱們使用社區版足矣。git

筆者這裏直接新建了一個文件夾,建立了一個名爲 spider-demo.py 的文件,這個就是咱們一會要寫的爬蟲的文件了,能夠給你們看下筆者的開發環境,以下:github

這實際上是一個調試成功的截圖,從下面打印的日誌中能夠看到,筆者這裏抓取了三個平臺的數據。sql

4. 數據庫

筆者使用的數據是 Mysql 5.7.19 版本,數據庫的字符集是使用的 utf8mb4 ,至於爲何使用 utf8mb4 而不是 utf8 ,各位百度一下吧,不少人講的都比我講的好,我簡單說一句就是 Mysql 的 utf8 實際上是一個假的 utf8 ,然後面增長的字符集 utf8mb4 纔是真正的 utf8 。數據庫

而 Python 鏈接 Mysql 也是須要驅動的,和在 Java 中鏈接數據庫須要驅動同樣,這裏使用的是 pymysql ,安裝命令:後端

pip install pymysql

有沒有感受很簡單, pip 是 Python 的一個包管理工具,個人我的理解是相似於一個 Maven 的東西,全部的咱們須要的第三方的包都能在這個上面下載到。瀏覽器

固然,這裏可能會出現 timeout 的狀況,視你們的網絡狀況而定,我在晚上執行這個命令的時候真的是各類 timeout ,固然 Maven 會有國內的鏡像戰, pip 顯然確定也會有麼,這裏都列給你們:

具體使用方式命令以下:

pip install -i https://mirrors.aliyun.com/pypi/simple/ 庫名

筆者這裏僅僅嘗試過阿里雲和清華大學的鏡像站,其他未作嘗試,以上內容來自於網絡。

表結構,設計以下圖,這裏設計很粗糙的,簡簡單單的只作了一張表,多餘話我也不說,你們看圖吧,字段後面都有註釋了:

建表語句提交至 Github 倉庫,有須要的同窗能夠去查看。

5. 實戰

總體思路分如下這麼幾步:

  1. 經過 GET 請求將整個頁面的 HTML 靜態資源請求回來
  2. 經過一些匹配規則匹配到咱們須要的數據
  3. 存入數據庫

5.1 請求 HTML 靜態資源

Python3 爲咱們提供了 urllib 這個標準庫,無需咱們額外的安裝,使用的時候須要先引入:

from urllib import request

接下來咱們使用 urllib 發送 GET 請求,以下:

req_csdn = request.Request('https://blog.csdn.net/meteor_93')
req_csdn.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36')
html_csdn = request.urlopen(req_csdn).read().decode('utf-8')

User Agent中文名爲用戶代理,簡稱 UA,它是一個特殊字符串頭,使得服務器可以識別客戶使用的操做系統及版本、CPU 類型、瀏覽器及版本、瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等。

這裏在請求頭中添加這個是爲了模擬瀏覽器正常請求,不少服務器都會作檢測,發現不是正常瀏覽器的請求會直接拒絕,雖而後面實測筆者爬取的這幾個平臺都沒有這項檢測,可是能加就加一下麼,固然真實的瀏覽器發送的請求頭裏面不只僅只有一個 UA ,還會有一些其餘的信息,以下圖:

筆者這裏的 UA 信息是直接從這裏 Copy 出來的。代碼寫到這裏,咱們已經拿到了頁面靜態資源 html_csdn ,接下來咱們就是要解析這個資源,從中匹配出來咱們須要的信息。

5.2 xpath 數據匹配

xpath 是什麼?

XPath 是一門在 XML 文檔中查找信息的語言。XPath 可用來在 XML 文檔中對元素和屬性進行遍歷。 XPath 是 W3C XSLT 標準的主要元素,而且 XQuery 和 XPointer 都構建於 XPath 表達之上。

從上面這句話咱們能夠看出來, xpath 是用來查找 XML ,而咱們的 HTML 能夠認爲是語法不標準的 XML 文檔,恰巧咱們能夠經過這種方式來解析 HTML 文檔。

咱們在使用 xpath 以前,須要先安裝 xpath 的依賴庫,這個庫並非 Python 提供的標準庫,安裝語句以下:

pip install lxml

若是網絡不給力的同窗可使用上面的鏡像站進行安裝。

而 xpath 的表達式很是簡單,具體的語法你們能夠參考 W3school 提供的教程(https://www.w3school.com.cn/xpath/xpath_syntax.asp ),筆者這裏很少介紹,具體使用方式以下:

read_num_csdn = etree.HTML(html_csdn).xpath('//*[@id="asideProfile"]/div[3]/dl[2]/dd/@title')[0]
fans_num_csdn = etree.HTML(html_csdn).xpath('//*[@id="fan"]/text()')[0]
rank_num_csdn = etree.HTML(html_csdn).xpath('//*[@id="asideProfile"]/div[3]/dl[4]/@title')[0]
like_num_csdn = etree.HTML(html_csdn).xpath('//*[@id="asideProfile"]/div[2]/dl[3]/dd/span/text()')[0]

這裏筆者主要獲取了總閱讀數、總粉絲數、排名和總點贊數。

這裏列舉幾個最基礎的使用,這幾個使用在本示例中已經徹底夠用:

表達式 描述
nodename 選取此節點的全部子節點。
/ 從根節點選取。
// 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。
. 選取當前節點。
.. 選取當前節點的父節點。
@ 選取屬性。
text 選取當前節點內容。

還有一種簡單的方式,咱們能夠經過 Chrome 瀏覽器獲取 xpath 表達式,具體操做見截圖:

打開 F12 ,鼠標右鍵須要生成 xpath 表達式的內容,點擊 Copy -> Copy XPath 便可。

這裏有一點須要注意,咱們直接經過 xpath 取出來的數據數據類型並非基礎數據類型,若是要作運算或者字符串拼接,須要作類型強轉,不然會報錯,以下:

req_cnblog = request.Request('https://www.cnblogs.com/babycomeon/default.html?page=2')
req_cnblog.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36')
html_cnblog = request.urlopen(req_cnblog).read().decode('utf-8')

max_page_num = etree.HTML(html_cnblog).xpath('//*[@id="homepage_top_pager"]/div/text()')

# 最大頁數
max_page_num = re.findall(r"\d+\.?\d*", str(max_page_num))[0]

這裏須要獲取 cnblog 的博客最大頁數,首先取到了 max_page_num ,這裏直接作 print 的話是能夠正常打印一個字符串出來的,可是若是直接去作正則匹配,就會類型錯誤。

5.3 寫入數據庫

數據庫的操做我就很少作介紹了,有寫過 Java 的同窗應該都很清楚 jdbc 是怎麼寫的,先使用 ip 、 port 、 用戶名、密碼、數據庫名稱、字符集等信息獲取鏈接,而後開啓鏈接,寫一句 sql ,把 sql 拼好,執行 sql ,而後提交數據,而後關閉鏈接,代碼以下:

def connect():
    conn = pymysql.connect(host='localhost',
                           port=3306,
                           user='root',
                           password='123456',
                           database='test',
                           charset='utf8mb4')

    # 獲取操做遊標
    cursor = conn.cursor()
    return {"conn": conn, "cursor": cursor}

connection = connect()
conn, cursor = connection['conn'], connection['cursor']

sql_insert = "insert into spider_data(id, plantform, read_num, fans_num, rank_num, like_num, create_date) values (UUID(), %(plantform)s, %(read_num)s, %(fans_num)s, %(rank_num)s, %(like_num)s, now())"

在本示例中,爬蟲只負責一個數據爬取工做,因此只須要一句 insert 語句就夠了,而後在每一個平臺爬取完成後,將這句 sql 中的佔位符替換掉,執行 sql 後 commit 操做便可,示例代碼以下:

csdn_data = {
    "plantform": 'csdn',
    "read_num": read_num_csdn,
    "fans_num": fans_num_csdn,
    "rank_num": rank_num_csdn,
    "like_num": like_num_csdn
}

cursor.execute(sql_insert, csdn_data)
conn.commit()

6. 小結

通過這麼一次 Python 爬蟲的實際體驗後,確實感受使用 Python 寫程序語法很是的簡單,總體程序使用 130+ 行,大體估算一下,若是使用 Java 書寫一樣的功能,可能會須要 200+ 行,使用 httpClient 發送 GET 請求再解析響應就不是這麼 Python 這種簡簡單單的 2~3 行代碼搞的定的。本示例的爬蟲其實還很是的不完善,目前只能爬取不須要登陸的平臺的數據,有的平臺須要登陸後才能看到統計數據,這就要和 Cookies 相結合才能完成模擬登錄的過程。後續有空我會接着完善這隻小爬蟲的。

本次的 Python 爬蟲更多的相似於一個技術嚐鮮,其中大量的代碼都是經過搜索引擎得到,其中的寫法有些懵懵懂懂,筆者決定後續系統的學習一下 Python ,屆時會分享一些學習過程出來,有興趣的小夥伴能夠跟着筆者一塊兒學習、討論。

老規矩,本篇的代碼也提交至 Github 倉庫和 Gitee 倉庫,有須要的朋友能夠自行索取,倉庫命名爲 python-learn ,也算是對本身學習的一種監督吧,每次學習的示例代碼都會提交至這個倉庫。

7. 示例代碼

示例代碼-Github

示例代碼-Gitee

8. 參考:

XPath 教程

原文出處:https://www.cnblogs.com/babycomeon/p/11651888.html

相關文章
相關標籤/搜索