什么是爬蟲|Python爬蟲的原理是什么

前言

簡單來說互聯(lián)網(wǎng)是由一個個站點和網(wǎng)絡(luò)設(shè)備組成的大網(wǎng)贷岸,我們通過瀏覽器訪問站點壹士,站點把HTML、JS偿警、CSS代碼返回給瀏覽器躏救,這些代碼經(jīng)過瀏覽器解析、渲染户敬,將豐富多彩的網(wǎng)頁呈現(xiàn)我們眼前落剪;

一睁本、爬蟲是什么尿庐?

如果我們把互聯(lián)網(wǎng)比作一張大的蜘蛛網(wǎng),數(shù)據(jù)便是存放于蜘蛛網(wǎng)的各個節(jié)點呢堰,而爬蟲就是一只小蜘蛛抄瑟,

沿著網(wǎng)絡(luò)抓取自己的獵物(數(shù)據(jù))爬蟲指的是:向網(wǎng)站發(fā)起請求,獲取資源后分析并提取有用數(shù)據(jù)的程序枉疼;

從技術(shù)層面來說就是 通過程序模擬瀏覽器請求站點的行為皮假,把站點返回的HTML代碼/JSON數(shù)據(jù)/二進(jìn)制數(shù)據(jù)(圖片、視頻) 爬到本地骂维,進(jìn)而提取自己需要的數(shù)據(jù)惹资,存放起來使用;

image

二航闺、爬蟲的基本流程:

用戶獲取網(wǎng)絡(luò)數(shù)據(jù)的方式:

方式1:瀏覽器提交請求--->下載網(wǎng)頁代碼--->解析成頁面

方式2:模擬瀏覽器發(fā)送請求(獲取網(wǎng)頁代碼)->提取有用的數(shù)據(jù)->存放于數(shù)據(jù)庫或文件中

爬蟲要做的就是方式2褪测;

image

1猴誊、發(fā)起請求

使用http庫向目標(biāo)站點發(fā)起請求,即發(fā)送一個Request

Request包含:請求頭侮措、請求體等

Request模塊缺陷:不能執(zhí)行JS 和CSS 代碼

2懈叹、獲取響應(yīng)內(nèi)容

如果服務(wù)器能正常響應(yīng),則會得到一個Response

Response包含:html分扎,json澄成,圖片,視頻等

3畏吓、解析內(nèi)容

解析html數(shù)據(jù):正則表達(dá)式(RE模塊)墨状,第三方解析庫如Beautifulsoup,pyquery等

解析json數(shù)據(jù):json模塊

解析二進(jìn)制數(shù)據(jù):以wb的方式寫入文件

4庵佣、保存數(shù)據(jù)

數(shù)據(jù)庫(MySQL歉胶,Mongdb、Redis)

文件

三巴粪、http協(xié)議 請求與響應(yīng)

image

Request:用戶將自己的信息通過瀏覽器(socket client)發(fā)送給服務(wù)器(socket server)

Response:服務(wù)器接收請求通今,分析用戶發(fā)來的請求信息,然后返回數(shù)據(jù)(返回的數(shù)據(jù)中可能包含其他鏈接肛根,如:圖片辫塌,js,css等)

ps:瀏覽器在接收Response后派哲,會解析其內(nèi)容來顯示給用戶臼氨,而爬蟲程序在模擬瀏覽器發(fā)送請求然后接收Response后,是要提取其中的有用數(shù)據(jù)芭届。

四储矩、 request

1、請求方式:

常見的請求方式:GET / POST

2褂乍、請求的URL

url全球統(tǒng)一資源定位符持隧,用來定義互聯(lián)網(wǎng)上一個唯一的資源 例如:一張圖片、一個文件逃片、一段視頻都可以用url唯一確定

url編碼

https://www.baidu.com/s?wd=圖片

圖片會被編碼(看示例代碼)

網(wǎng)頁的加載過程是:

加載一個網(wǎng)頁屡拨,通常都是先加載document文檔,

在解析document文檔的時候褥实,遇到鏈接呀狼,則針對超鏈接發(fā)起下載圖片的請求

3、請求頭

User-agent:請求頭中如果沒有user-agent客戶端配置损离,服務(wù)端可能將你當(dāng)做一個非法用戶host哥艇;

cookies:cookie用來保存登錄信息

注意: 一般做爬蟲都會加上請求頭

image
image
image

請求頭需要注意的參數(shù):

(1)Referrer:訪問源至哪里來(一些大型網(wǎng)站,會通過Referrer 做防盜鏈策略僻澎;所有爬蟲也要注意模擬)

(2)User-Agent:訪問的瀏覽器(要加上否則會被當(dāng)成爬蟲程序)

(3)cookie:請求頭注意攜帶

4貌踏、請求體

請求體
    如果是get方式瓮增,請求體沒有內(nèi)容 (get請求的請求體放在 url后面參數(shù)中,直接能看到)
    如果是post方式哩俭,請求體是format data

    ps:
    1绷跑、登錄窗口,文件上傳等凡资,信息都會被附加到請求體內(nèi)
    2砸捏、登錄,輸入錯誤的用戶名密碼隙赁,然后提交垦藏,就可以看到post,正確登錄后頁面通常會跳轉(zhuǎn)伞访,無法捕捉到post

五掂骏、 響應(yīng)Response

1、響應(yīng)狀態(tài)碼

200:代表成功

301:代表跳轉(zhuǎn)

404:文件不存在

403:無權(quán)限訪問

502:服務(wù)器錯誤

2厚掷、respone header

響應(yīng)頭需要注意的參數(shù):

(1)Set-Cookie:BDSVRTM=0; path=/:可能有多個弟灼,是來告訴瀏覽器,把cookie保存下來

(2)Content-Location:服務(wù)端響應(yīng)頭中包含Location返回瀏覽器之后冒黑,瀏覽器就會重新訪問另一個頁面

3田绑、preview就是網(wǎng)頁源代碼

JSO數(shù)據(jù)

如網(wǎng)頁html,圖片

二進(jìn)制數(shù)據(jù)等

六抡爹、總結(jié)

1掩驱、總結(jié)爬蟲流程:

爬取--->解析--->存儲

2、爬蟲所需工具:

請求庫:requests,selenium(可以驅(qū)動瀏覽器解析渲染CSS和JS冬竟,但有性能劣勢(有用沒用的網(wǎng)頁都會加載)欧穴;)
解析庫:正則,beautifulsoup泵殴,pyquery
存儲庫:文件涮帘,MySQL,Mongodb袋狞,Redis

3焚辅、爬獲杏澄荩花網(wǎng)

最后送給大家點福利吧
image

基礎(chǔ)版:

import re
import requests

respose\=requests.get('http://www.xiaohuar.com/v/')
# print(respose.status\_code)# 響應(yīng)的狀態(tài)碼
# print(respose.content)  #返回字節(jié)信息
# print(respose.text)  #返回文本內(nèi)容
urls=re.findall(r'class="items".\*?href="(.\*?)"',respose.text,re.S)  #re.S 把文本信息轉(zhuǎn)換成1行匹配
url=urls\[5\]
result\=requests.get(url)
mp4\_url\=re.findall(r'id="media".\*?src="(.\*?)"',result.text,re.S)\[0\]

video\=requests.get(mp4\_url)

with open('D:\\\\a.mp4','wb') as f:
    f.write(video.content)

View Code

函數(shù)封裝版

import re
import requests
import hashlib
import time

# respose=requests.get('http://www.xiaohuar.com/v/')
# # print(respose.status\_code)# 響應(yīng)的狀態(tài)碼
# # print(respose.content)  #返回字節(jié)信息
# # print(respose.text)  #返回文本內(nèi)容
# urls=re.findall(r'class="items".\*?href="(.\*?)"',respose.text,re.S)  #re.S 把文本信息轉(zhuǎn)換成1行匹配
# url=urls\[5\]
# result=requests.get(url)
# mp4\_url=re.findall(r'id="media".\*?src="(.\*?)"',result.text,re.S)\[0\]
#
# video=requests.get(mp4\_url)
#
# with open('D:\\\\a.mp4','wb') as f:
#     f.write(video.content)
#

def get\_index(url):
    respose \= requests.get(url)
    if respose.status\_code==200:
        return respose.text

def parse\_index(res):
    urls \= re.findall(r'class="items".\*?href="(.\*?)"', res,re.S)  # re.S 把文本信息轉(zhuǎn)換成1行匹配
    return urls

def get\_detail(urls):
    for url in urls:
        if not url.startswith('http'):
            url\='http://www.xiaohuar.com%s' %url
        result \= requests.get(url)
        if result.status\_code==200 :
            mp4\_url\_list \= re.findall(r'id="media".\*?src="(.\*?)"', result.text, re.S)
            if mp4\_url\_list:
                mp4\_url\=mp4\_url\_list\[0\]
                print(mp4\_url)
                # save(mp4\_url)

def save(url):
    video \= requests.get(url)
    if video.status\_code==200:
        m\=hashlib.md5()
        m.updata(url.encode('utf-8'))
        m.updata(str(time.time()).encode('utf-8'))
        filename\=r'%s.mp4'% m.hexdigest()
        filepath\=r'D:\\\\%s'%filename
        with open(filepath, 'wb') as f:
            f.write(video.content)

def main():
    for i in range(5):
        res1 \= get\_index('http://www.xiaohuar.com/list-3-%s.html'% i )
        res2 \= parse\_index(res1)
        get\_detail(res2)

if \_\_name\_\_ == '\_\_main\_\_':
    main()

View Code

并發(fā)版(如果一共需要爬30個視頻苟鸯,開30個線程去做,花的時間就是 其中最慢那份的耗時時間)

import re
import requests
import hashlib
import time
from concurrent.futures import ThreadPoolExecutor
p\=ThreadPoolExecutor(30) #創(chuàng)建1個程池中棚点,容納線程個數(shù)為30個早处;

def get\_index(url):
    respose \= requests.get(url)
    if respose.status\_code==200:
        return respose.text

def parse\_index(res):
    res\=res.result() #進(jìn)程執(zhí)行完畢后,得到1個對象
    urls = re.findall(r'class="items".\*?href="(.\*?)"', res,re.S)  # re.S 把文本信息轉(zhuǎn)換成1行匹配
    for url in urls:
        p.submit(get\_detail(url))  #獲取詳情頁 提交到線程池

def get\_detail(url):  #只下載1個視頻
        if not url.startswith('http'):
            url\='http://www.xiaohuar.com%s' %url
        result \= requests.get(url)
        if result.status\_code==200 :
            mp4\_url\_list \= re.findall(r'id="media".\*?src="(.\*?)"', result.text, re.S)
            if mp4\_url\_list:
                mp4\_url\=mp4\_url\_list\[0\]
                print(mp4\_url)
                # save(mp4\_url)

def save(url):
    video \= requests.get(url)
    if video.status\_code==200:
        m\=hashlib.md5()
        m.updata(url.encode('utf-8'))
        m.updata(str(time.time()).encode('utf-8'))
        filename\=r'%s.mp4'% m.hexdigest()
        filepath\=r'D:\\\\%s'%filename
        with open(filepath, 'wb') as f:
            f.write(video.content)

def main():
    for i in range(5):
        p.submit(get\_index,'http://www.xiaohuar.com/list-3-%s.html'% i ).add\_done\_callback(parse\_index)
        #1瘫析、先把爬主頁的任務(wù)(get\_index)異步提交到線程池
        #2砌梆、get\_index任務(wù)執(zhí)行完后默责,會通過回調(diào)函add\_done\_callback()數(shù)通知主線程,任務(wù)完成咸包;
        #2桃序、把get\_index執(zhí)行結(jié)果(注意線程執(zhí)行結(jié)果是對象,調(diào)用res=res.result()方法烂瘫,才能獲取真正執(zhí)行結(jié)果)媒熊,當(dāng)做參數(shù)傳給parse\_index
        #3、parse\_index任務(wù)執(zhí)行完畢后坟比,
        #4芦鳍、通過循環(huán),再次把獲取詳情頁 get\_detail()任務(wù)提交到線程池執(zhí)行

if \_\_name\_\_ == '\_\_main\_\_':
    main()

View Code

涉及知識:多線程多進(jìn)程

計算密集型任務(wù):使用多進(jìn)程葛账,因為能Python有GIL柠衅,多進(jìn)程可以利用上CPU多核優(yōu)勢;

IO密集型任務(wù):使用多線程籍琳,做IO切換節(jié)省任務(wù)執(zhí)行時間(并發(fā))

線程池

無論如何菲宴,非常感謝您閱讀我的文章!有任何問題可以后臺私信我趋急,有問必答裙顽!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市宣谈,隨后出現(xiàn)的幾起案子愈犹,更是在濱河造成了極大的恐慌,老刑警劉巖闻丑,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漩怎,死亡現(xiàn)場離奇詭異,居然都是意外死亡嗦嗡,警方通過查閱死者的電腦和手機勋锤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侥祭,“玉大人叁执,你說我怎么就攤上這事“” “怎么了谈宛?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長胎署。 經(jīng)常有香客問我吆录,道長,這世上最難降的妖魔是什么琼牧? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任恢筝,我火速辦了婚禮哀卫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘撬槽。我一直安慰自己此改,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布侄柔。 她就那樣靜靜地躺著带斑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勋拟。 梳的紋絲不亂的頭發(fā)上勋磕,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音敢靡,去河邊找鬼挂滓。 笑死,一個胖子當(dāng)著我的面吹牛啸胧,可吹牛的內(nèi)容都是我干的赶站。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼纺念,長吁一口氣:“原來是場噩夢啊……” “哼贝椿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起陷谱,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤烙博,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后烟逊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渣窜,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年宪躯,在試婚紗的時候發(fā)現(xiàn)自己被綠了乔宿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡访雪,死狀恐怖详瑞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情臣缀,我是刑警寧澤坝橡,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站肝陪,受9級特大地震影響驳庭,放射性物質(zhì)發(fā)生泄漏刑顺。R本人自食惡果不足惜氯窍,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一饲常、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狼讨,春花似錦贝淤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至布隔,卻和暖如春离陶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背衅檀。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工招刨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哀军。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓沉眶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親杉适。 傳聞我的和親對象是個殘疾皇子谎倔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容