最詳細的Python爬蟲入門教程,一篇文章入門爬蟲不是兒戲!

来源:https://www.cnblogs.com/kongshouyisuiyue/archive/2018/09/05/9595424.html
-Advertisement-
Play Games

0×00 介紹 0×01 要求 0×02 你能學到什麼? 0×03 知識補充 0×04 最簡單的開始 0×05 更優雅的解決方案 0×06 url合法性判斷 0×07 總結與預告 0×00 介紹 學習Python中有不明白推薦加入交流群 號:548377875 群里有志同道合的小伙伴,互幫互助, 群 ...


 

最詳細的Python爬蟲入門教程,一篇文章入門爬蟲不是兒戲!

 

0×00 介紹

0×01 要求

0×02 你能學到什麼?

0×03 知識補充

0×04 最簡單的開始

0×05 更優雅的解決方案

0×06 url合法性判斷

0×07 總結與預告

0×00 介紹

學習Python中有不明白推薦加入交流群
號:548377875
群里有志同道合的小伙伴,互幫互助,
群里有不錯的學習教程!

爬蟲技術是數據挖掘,測試技術的重要的組成部分,是搜索引擎技術的核心。

最詳細的Python爬蟲入門教程,一篇文章入門爬蟲不是兒戲!

 

但是作為一項普通的技術,普通人同樣可以用爬蟲技術做很多很多的事情,比如:你想瞭解一下某網所有關於爬蟲技術的文章,你就可以編寫爬蟲去對文章進行搜索,解析。比如你想獲得淘寶某類商品的價格,你可以編寫爬蟲自動搜索某類商品,然後獲取信息,得到自己想要的結果,每天定時爬一下自己就可以決定在什麼時候低價的時候買下心儀的商品了。或者說自己想收集某類信息集合成自己的資料庫,但是手動複製粘貼特別的麻煩,這時候爬蟲技術就可以幫上大忙了對不對?

0×01 要求(私信小編007即可獲取大量Python學習資料)

 

那麼本系列文章旨在普及爬蟲技術,當然不是那種直接拿來爬蟲框架來說明的。在本系列文章中,筆者儘力從簡到難,簡明地介紹爬蟲的各種要素,怎麼樣快速編寫對自己有用的代碼。但是對讀者有一定小小的要求:看得懂python代碼,然後自己能動手實踐一些,除此之外,還要對html元素有一定的瞭解。

0×02 你能學到什麼?

當然爬蟲的文章在網上很容易找到,但是精緻,系統地講解的文章還是比較少,筆者在本文和今後的文章將介紹關於爬蟲的各種各樣的知識:

大致上,本文的寫作順序是單機爬蟲到分散式爬蟲,功能實現到整體設計,從微觀到巨集觀。

1. 簡單模塊編寫簡單爬蟲

2. 相對優雅的爬蟲

3. 爬蟲基本理論以及一般方法

4. 簡單Web數據挖掘

5. 動態web爬蟲(可以處理js的爬蟲)

6. 爬蟲的數據存儲

7. 多線程與分散式爬蟲設計

如果有讀者想找一些爬蟲的入門書籍來看,我推薦《web scraping with python》,這本書是英文版目前沒有中文譯本,但是網上有愛好者在翻譯,有興趣的讀者可以瞭解一下。

0×03 知識補充

在這裡的知識補充我其實是要簡單介紹目前主流的幾種爬蟲編寫用的模塊:

Htmllib(sgmllib),這個模塊是非常古老的一個模塊,偏底層,實際就是簡單解析html文檔而已,不支持搜索標簽,容錯性也比較差,這裡指的提醒的是,如果傳入的html文檔沒有正確結束的話,這個模塊是不會解析的,直到正確的數據傳入或者說強行關閉。

BeautifulSoup,這個模塊解析html非常專業,具有很好的容錯性,可以搜索任意標簽,自帶編碼處理方案。

Selenium,自動化web測試方案解決者,類似BeautifulSoup,但是不一樣的是,selenium自帶了js解釋器,也就是說selenium配合瀏覽器可以用來做動態網頁的爬取,分析,挖掘。

Scrapy框架:一個專業的爬蟲框架(單機),有相對完整的解決方案。

API爬蟲:這裡大概都是需要付費的爬蟲API,比如google,twitter的解決方案,就不在介紹。

筆者在文章中只會出現前三種方式來做爬蟲編寫。

0×04 最簡單的開始

最開始的一個例子,我將會先介紹最簡單的模塊,編寫最簡單的單頁爬蟲:

Urllib這個模塊我們這裡用來獲取一個頁面的html文檔,具體的使用是,

Web = urllib.urlopen(url)

Data = Web.read()

要註意的是,這是py2的寫法,py3是不一樣的。

Smgllib這個庫是htmllib的底層,但是也可以提供一個對html文本的解析方案,具體的使用方法是:

1. 自定義一個類,繼承sgmllib的SGMLParser;

2. 覆寫SGMLParser的方法,添加自己自定義的標簽處理函數

3. 通過自定義的類的對象的.feed(data)把要解析的數據傳入解析器,然後自定義的方法自動生效。

import urllib
import sgmllib

class handle_html(sgmllib.SGMLParser):
#unknown_starttag這個方法在任意的標簽開始被解析時調用
#tag為標簽名
#attrs表示標簽的參賽
def unknown_starttag(self, tag, attrs):
print "-------"+tag+" start--------"
print attrs
#unknown_endtag這個方法在任意標簽結束被解析時被調用
def unknown_endtag(self, tag):
print "-------"+tag+" end----------"

web =urllib.urlopen("http://freebuf.com/")
web_handler = handle_html()
#數據傳入解析器
web_handler.feed(web.read())

短短十幾行代碼,最簡單的單頁面爬蟲就完成了,以下是輸出的效果。我們可以看到標簽開始和結束都被標記了。然後同時列印出了每一個參數。

最詳細的Python爬蟲入門教程,一篇文章入門爬蟲不是兒戲!

 

 

接下來我們可以使用這種底層的解析方式來做個基礎的小例子:

下麵這個小例子在標簽開始的時候檢查標簽中的attrs屬性,解析出所有的參數的href屬性,知道的讀者都知道這基本是被一個爬蟲的必經之路。

import urllib
import sgmllib

class handle_html(sgmllib.SGMLParser):
defunknown_starttag(self, tag, attrs):
#這裡利用try與except來避免報錯。
#但是並不推薦這樣做,
#對於這種小腳本雖然無傷大雅,但是在實際的項目處理中,
#這種做法存在很大的隱患
try:
for attr in attrs:
if attr[0] == "href":
printattr[0]+":"+attr[1].encode('utf-8')
except:
pass

web =urllib.urlopen("http://freebuf.com/")
web_handler = handle_html()
web_handler.feed(web.read())

解析結果為:

最詳細的Python爬蟲入門教程,一篇文章入門爬蟲不是兒戲!

 

 

我們發現在解析出的href種,存在一些不和諧的因素,比如JavaScript的出現,比如其他功能變數名稱的出現,或者有些讀者說的,url有重覆。實際上,這是對於我們的FreeBuf站來說,但是對於互聯網上的各種複雜環境來說,上面的考慮是完全不夠的。關於這一點我們稍後再做討論。

但是筆者並不計劃就用這個方法來把我們的問題處理完全。因為我們有更優雅的解決方案。

0×05 更優雅的解決方案

當然我說的時BeautifulSoup,為什麼選用這個模塊呢?筆者私認為這個模塊解析html非常專業,這裡簡稱bs4,讀過bs4的讀者都很清楚。實際上beautifulsoup並不只是簡單的解析html文檔,實際上裡面大有玄機:五種解析器自動選擇或者手動指定,每個解析器的偏重方向都不一樣,有的偏重速度,有的偏重正確率。自動識別html文檔的編碼,並且給出非常完美的解決方案,支持css篩選,各種參數的方便使用。

BeautifulSoup的一般使用步驟:

1. 導入beatifulsoup庫 :from bs4 import BeautifulSoup

2. 傳入數據,建立對象: soup = BeautifulSoup(data),

3. 操作soup,完成需求解析。

下麵我們來看具體的代碼實例:

from bs4 import BeautifulSoup
import urllib
import re
web =urllib.urlopen("http://freebuf.com/")
soup = BeautifulSoup(web.read())
tags_a =soup.findAll(name="a",attrs={'href':re.compile("^https?://")})
for tag_a in tags_a:
printtag_a["href"]

這一段與sgmllib的第二短代碼相同功能,但寫起來就更加的優雅。然後還引入了正則表達式,稍微過濾下鏈接的表達式,過濾掉了JavaScript字樣,顯然看起來簡煉多了:

最詳細的Python爬蟲入門教程,一篇文章入門爬蟲不是兒戲!

 

 

簡單解釋一下上面的warning:

UserWarning: No parser was explicitlyspecified, so I’m using the best available HTML parser for this system(“html.parser”). This usually isn’t a problem, but if you run thiscode on another system, or in a different virtual environment, it may use adifferent parser and behave differently.

To get rid of this warning, change this:

BeautifulSoup([your markup])

to this:

BeautifulSoup([your markup],”html.parser”)

上面的內容是說:沒有特別指明解析器,bs4使用了它認為最好的解析器html.parser,這一般不會出問題,但是如果你在不同的環境下運行,可能解析器是不一樣的。要移除這個warning可以修改你的beautifulsoup選項改成BeautifulSoup(data, “html.parser”)

這個warning表明瞭bs4的自動選擇解析器來解析的特性。

0×06 url和合法性判斷

url與uri其實是一個東西,如果但是我們更多的不提uri,那麼我們來說一下關於url的處理:如果說像我們一開始那樣做的話,我們手動,或者通過正則去分析每一個url,我們要考慮url的各種結構,比如下麵這些例子:

path?ss=1#arch
http://freebuf.com/geek
?ss=1
path/me
javascript:void(0)
/freebuf.com/s/s/s/
sssfadea://ssss.ss
path?ss=1&s=1
ftp://freeme.com/ss/s/s
path?ss=1
#arch
//freebuf.com/s/s/s/
https://freebuf.com:443/geek?id=1#sid
//freebuf.com/s/s/s

我們大概就是要處理這麼多的不同形式的url,這些都是在網頁上非常有可能出現的url,那麼,那麼我們怎麼判斷這些的合法性呢?

先以//分開,左邊時協議+‘:’,右邊到第一個’/’是功能變數名稱,功能變數名稱後面時路徑,?後面時參數,#後面是錨點。

這麼分析來的話寫代碼判斷應該不是一個特別困難的事情,但是我們並沒有必要每次都去寫代碼解決這個問題啊,畢竟我們在使用python,這些事情並不需要自己來做,

其實我個人覺得這個要得益於python強大的模塊:urlparser,這個模塊就是把我們上面的url分析思路做了實現,用法也是pythonic:

import urlparse
url = set()
url.add('javascript:void(0)')
url.add('http://freebuf.com/geek')
url.add('https://freebuf.com:443/geek?id=1#sid')
url.add('ftp://freeme.com/ss/s/s')
url.add('sssfadea://ssss.ss')
url.add('//freebuf.com/s/s/s')
url.add('/freebuf.com/s/s/s/')
url.add('//freebuf.com/s/s/s/')
url.add('path/me')
url.add('path?ss=1')
url.add('path?ss=1&s=1')
url.add('path?ss=1#arch')
url.add('?ss=1')
url.add('#arch')
for item in url:
print item
o= urlparse.urlparse(item)
print o
print

然後執行代碼,我們可以看一下具體的解析結果:

import urlparse
url = set()
url.add('javascript:void(0)')
url.add('http://freebuf.com/geek')
url.add('https://freebuf.com:443/geek?id=1#sid')
url.add('ftp://freeme.com/ss/s/s')
url.add('sssfadea://ssss.ss')
url.add('//freebuf.com/s/s/s')
url.add('/freebuf.com/s/s/s/')
url.add('//freebuf.com/s/s/s/')
url.add('path/me')
url.add('path?ss=1')
url.add('path?ss=1&s=1')
url.add('path?ss=1#arch')
url.add('?ss=1')
url.add('#arch')
for item in url:
print item
o= urlparse.urlparse(item)
print o
printpath?ss=1#arch
ParseResult(scheme='', netloc='',path='path', params='', query='ss=1', fragment='arch')

http://freebuf.com/geek
ParseResult(scheme='http',netloc='freebuf.com', path='/geek', params='', query='', fragment='')

?ss=1
ParseResult(scheme='', netloc='', path='',params='', query='ss=1', fragment='')

path/me
ParseResult(scheme='', netloc='',path='path/me', params='', query='', fragment='')

javascript:void(0)
ParseResult(scheme='javascript', netloc='',path='void(0)', params='', query='', fragment='')

/freebuf.com/s/s/s/
ParseResult(scheme='', netloc='', path='/freebuf.com/s/s/s/',params='', query='', fragment='')

sssfadea://ssss.ss
ParseResult(scheme='sssfadea',netloc='ssss.ss', path='', params='', query='', fragment='')

path?ss=1&s=1
ParseResult(scheme='', netloc='',path='path', params='', query='ss=1&s=1', fragment='')

ftp://freeme.com/ss/s/s
ParseResult(scheme='ftp',netloc='freeme.com', path='/ss/s/s', params='', query='', fragment='')

path?ss=1
ParseResult(scheme='', netloc='',path='path', params='', query='ss=1', fragment='')

#arch
ParseResult(scheme='', netloc='', path='',params='', query='', fragment='arch')

//freebuf.com/s/s/s/
ParseResult(scheme='',netloc='freebuf.com', path='/s/s/s/', params='', query='', fragment='')

https://freebuf.com:443/geek?id=1#sid
ParseResult(scheme='https',netloc='freebuf.com:443', path='/geek', params='', query='id=1',fragment='sid')

//freebuf.com/s/s/s
ParseResult(scheme='',netloc='freebuf.com', path='/s/s/s', params='', query='', fragment='')

在urlparser返回的對象中我們可以直接以索引的方式拿到每一個參數的值。那麼我們這裡就有索引表了:

最詳細的Python爬蟲入門教程,一篇文章入門爬蟲不是兒戲!

 

這張表的用法,

o = urlparse.urlparse(url)

o[0]表示scheme

o[1]表示netloc

……

以此類推。

我們發現:

如果scheme和netloc都同時為空的話,該url可能是當前url+path

如果scheme不為空但是netloc為空的話,該url不合法

如果scheme為空但是netloc不為空的話,不一定不合法,要具體分析,一般情況下是http

如果只存在fragment或者query的話,該url為當前的url+query[+fragment]

……

那麼根據上面的規則,我們基本可以把無關的url或者不是url排除掉,或者恢復完整的url

0×07 總結與預告

本章中我們一起探究了一個簡單爬蟲的實現,然後稍微討論了一下如何處理頁面的url。相信讀者讀完本文的時候已經有了一定的對爬蟲的基礎認識,但是要知道,只瞭解到這種程度還不能說瞭解爬蟲,這隻是冰山一角。

在下一節中,我們將學到下麵的知識:

1、爬蟲道德與爬蟲的理論知識

2、sitemap爬蟲

3、簡單web數據處理

最詳細的Python爬蟲入門教程,一篇文章入門爬蟲不是兒戲!
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • liuyuhang原創,未經允許請勿轉載! 前端開發樹形插件帶來的煩惱(一) 前端開發中,有些項目中會用到樹形插件,其數據結構也比較簡單,大體如下: 數據結構說明: 每一行代表一個數據,該數據由基本信息,id,pid三個部分構成。pid為連接的父節點,額外增加的內容也包括兩個部分; ①縮進;②節點展 ...
  • spring知識的鞏固整理AOP和ioc概念,以及瞭解到了為何要使用spring框架的目的,作用:變換資源獲取的方向。更像是按需所求。配置bean的方式:利用XML的方式,基於註解的方式兩種。1通過全類名反射的方式,2通過工廠實例的方式,3 通過更底層的Beanfactory的方式依賴註入DI的方式 ...
  • 不知不覺中一年又走過了大半,不變的是技術依舊小白,唯一慶幸的是也沒有徹底停下腳步。 言歸正傳,今天總結記錄的是樓+學習中,挑戰一的兩個知識點。 1.from collections import namedtuple collections 是Python內建的一個集合模塊,提供了許多有用的集合類。 ...
  • 最近在項目中應用到springboot與mybatis,在進行整合過程中遇到一些坑,在此將其整理出來,便於以後查閱與複習。 項目運行環境為:eclispe+jdk1.8+maven 搭建Spring Boot環境 === 首先建立maven project,在生成的pom文件中加入依賴,代碼如下: ...
  • facebook atc介紹 Augmented Traffic Control(又名atc)是一種模擬網路狀況的工具。由facebook開源,是一個允許開發人員控制設備與互聯網連接的項目。atc可以模擬不同的網路條件,包括控制帶寬,延遲,數據包丟失、數據包損壞、數據包重排序等幾個因素都可以由atc ...
  • 線程池學習 以下所有內容以及源碼分析都是基於JDK1.8的,請知悉。 我寫博客就真的比較沒有順序了,這可能跟我的學習方式有關,我自己也覺得這樣挺不好的,但是沒辦法說服自己去改變,所以也只能這樣想到什麼學什麼了。 ​ 池化技術真的是一門在我看來非常牛逼的技術,因為它做到了在有限資源內實現了資源利用的最 ...
  • PHP生成一個六位數的邀請碼 $unique_no = substr(base_convert(md5(uniqid(md5(microtime(true)),true)), 16, 10), 0, 6); ...
  • 1.創建一個henan的空列表,添加zhengzhou,kaifeng,shangqiu,jiaozuo,xinyang元素; 2.在kaifeng元素前面插入一個luoyang元素; 3.把元素xinyang改成中文信陽; 4.在元素jiaozuo後面插入一個子列表[hebi,xuchang]; ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...