爬蟲基本原理

爬蟲是什么

什么是互聯(lián)網(wǎng)抱慌?

互聯(lián)網(wǎng)是由網(wǎng)絡(luò)設(shè)備(網(wǎng)線,路由器泣栈,交換機(jī)卜高,防火墻等等)和一臺臺計(jì)算機(jī)連接而成,像一張網(wǎng)一樣南片。

互聯(lián)網(wǎng)建立的目的掺涛?

互聯(lián)網(wǎng)的核心價(jià)值在于數(shù)據(jù)的共享/傳遞。

數(shù)據(jù)是存放于一臺臺計(jì)算機(jī)上的疼进,而將計(jì)算機(jī)互聯(lián)到一起的目的就是為了能夠方便彼此之間的數(shù)據(jù)共享/傳遞薪缆,否則你只能拿U盤去別人的計(jì)算機(jī)上拷貝數(shù)據(jù)了。

什么是上網(wǎng)伞广?爬蟲要做的是什么拣帽?

所謂的上網(wǎng)就是由客戶端計(jì)算機(jī)發(fā)送請求給服務(wù)器,將服務(wù)器的數(shù)據(jù)下載到本地的過程嚼锄。

用戶獲取網(wǎng)絡(luò)數(shù)據(jù)的方式:瀏覽器提交請求->下載網(wǎng)頁代碼->解析/渲染成頁面

爬蟲獲取網(wǎng)絡(luò)數(shù)據(jù)的方式:模擬瀏覽器發(fā)送請求->提取有用活動(dòng)數(shù)據(jù)->保存到數(shù)據(jù)庫/文件中

區(qū)別:爬蟲程序只提取網(wǎng)頁代碼中對我們有用的數(shù)據(jù)诞外。

如果把互聯(lián)網(wǎng)比作一張大的蜘蛛網(wǎng),那一臺計(jì)算機(jī)上的數(shù)據(jù)便是蜘蛛網(wǎng)上的一個(gè)獵物灾票,而爬蟲程序就是一只小蜘蛛,沿著蜘蛛網(wǎng)抓取自己想要的獵物/數(shù)據(jù)茫虽。

爬蟲的定義:向網(wǎng)站發(fā)起請求刊苍,獲取資源后分析并提取有用數(shù)據(jù)的程序既们。

爬蟲的價(jià)值:互聯(lián)網(wǎng)中最有價(jià)值的便是數(shù)據(jù),比如天貓商城的商品信息正什,鏈家網(wǎng)的租房信息啥纸,雪球網(wǎng)的證券投資信息等等,這些數(shù)據(jù)都代表了各個(gè)行業(yè)的真金白銀婴氮,可以說斯棒,誰掌握了行業(yè)內(nèi)的第一手?jǐn)?shù)據(jù),誰就成了整個(gè)行業(yè)的主宰主经,如果把整個(gè)互聯(lián)網(wǎng)的數(shù)據(jù)比喻為一座寶藏荣暮,那我們的爬蟲課程就是來教大家如何來高效地挖掘這些寶藏,掌握了爬蟲技能罩驻,你就成了所有互聯(lián)網(wǎng)信息公司幕后的老板穗酥,換言之,它們都在免費(fèi)為你提供有價(jià)值的數(shù)據(jù)惠遏。

爬蟲的基本流程

發(fā)送請求->獲取響應(yīng)內(nèi)容->解析內(nèi)容->保存數(shù)據(jù)

1. 發(fā)送請求

使用http庫向目標(biāo)站點(diǎn)發(fā)起請求砾跃,即發(fā)送一個(gè)Request

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

2. 獲取響應(yīng)內(nèi)容

如果服務(wù)器能正常響應(yīng)节吮,則會(huì)得到一個(gè)Response
Response包含:html抽高,json,圖片透绩,視頻等

3. 解析內(nèi)容

解析html數(shù)據(jù):正則表達(dá)式翘骂,第三方解析庫如Beautifulsoup,pyquery等

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

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

4. 保存數(shù)據(jù)

數(shù)據(jù)庫/文件

請求與響應(yīng)

http協(xié)議https://www.baidu.com/

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

Response:服務(wù)器接收請求渺贤,分析用戶發(fā)來的請求信息雏胃,然后返回?cái)?shù)據(jù)(返回的數(shù)據(jù)中可能包含其他鏈接,如:圖片志鞍,js瞭亮,css等)

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

Request

請求方式

常用的請求方式:GET此洲,POST
其他請求方式:HEAD厂汗,PUT,DELETE呜师,OPTHONS

post與get請求最終都會(huì)拼接成urlencode形式:k1=xxx&k2=yyy&k3=zzz
post請求的參數(shù)放在請求體內(nèi)娶桦,可用瀏覽器查看,存放于form data內(nèi)
get請求的參數(shù)直接放在url后

請求url

url全稱統(tǒng)一資源定位符,如一個(gè)網(wǎng)頁文檔衷畦,一張圖片栗涂,一個(gè)視頻等都可以用url唯一來確定

https://www.baidu.com/s?wd=圖片(其中的中文'圖片'會(huì)被編碼)

網(wǎng)頁的加載過程是:
加載一個(gè)網(wǎng)頁,通常都是先加載document文檔祈争,
在解析document文檔的時(shí)候斤程,遇到鏈接,則針對超鏈接發(fā)起下載圖片的請求

請求頭

Accept:text/html,application/xhtml+xml,application/xml;
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie:logged_in=no; tz=Asia%2FShanghai
Host:github.com
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 10

User-agent:請求頭中如果沒有user-agent客戶端配置菩混,服務(wù)端可能將你當(dāng)做一個(gè)非法用戶

cookies:cookie用來保存登錄信息

referer:從哪里跳來的

一般做爬蟲都會(huì)加上請求頭

請求體

如果是get方式忿墅,請求體沒有內(nèi)容
如果是post方式,請求體是Form Data

commit:Sign in
utf8:?
authenticity_token:LETizAkcEpnwCEUA6duyincUjGxpfNrZknwOUUmTVBPJfKMDGTwR3g2XbOEn5Yg==
login:111
password:222

ps:
1沮峡、登錄窗口疚脐,文件上傳等,信息都會(huì)被附加到請求體內(nèi)
2帖烘、登錄亮曹,輸入錯(cuò)誤的用戶名密碼,然后提交秘症,就可以看到post照卦,正確登錄后頁面通常會(huì)跳轉(zhuǎn),無法捕捉到post

Response

#1乡摹、響應(yīng)狀態(tài)
    200:代表成功
    301:代表跳轉(zhuǎn)
    404:文件不存在
    403:權(quán)限
    502:服務(wù)器錯(cuò)誤

#2役耕、Respone header
    set-cookie:可能有多個(gè),是來告訴瀏覽器聪廉,把cookie保存下來
    
#3瞬痘、preview就是網(wǎng)頁源代碼
    最主要的部分,包含了請求資源的內(nèi)容
    如網(wǎng)頁html板熊,圖片
    二進(jìn)制數(shù)據(jù)等

總結(jié)

#1框全、總結(jié)爬蟲流程:
    爬取--->解析--->存儲(chǔ)

#2、爬蟲所需工具:
    請求庫:requests,selenium
    解析庫:正則干签,beautifulsoup津辩,pyquery
    存儲(chǔ)庫:文件,MySQL容劳,Mongodb喘沿,Redis

#3、爬蟲常用框架:
    scrapy

爬取薪叻罚花網(wǎng)視頻

import requests
import re
import time
import hashlib

def get_page(url):
    print('GET %s' %url)
    try:
        response=requests.get(url)
        if response.status_code == 200:
            return response.content
    except Exception:
        pass

def parse_index(res):
    obj=re.compile('class="items.*?<a href="(.*?)"',re.S)
    detail_urls=obj.findall(res.decode('gbk'))
    for detail_url in detail_urls:
        if not detail_url.startswith('http'):
            detail_url='http://www.xiaohuar.com'+detail_url
        yield detail_url

def parse_detail(res):
    obj=re.compile('id="media".*?src="(.*?)"',re.S)
    res=obj.findall(res.decode('gbk'))
    if len(res) > 0:
        movie_url=res[0]
        return movie_url


def save(movie_url):
    response=requests.get(movie_url,stream=False)
    if response.status_code == 200:
        m=hashlib.md5()
        m.update(('%s%s.mp4' %(movie_url,time.time())).encode('utf-8'))
        filename=m.hexdigest()
        with open(r'./movies/%s.mp4' %filename,'wb') as f:
            f.write(response.content)
            f.flush()


def main():
    index_url='http://www.xiaohuar.com/list-3-{0}.html'
    for i in range(5):
        print('*'*50,i)
        #爬取主頁面
        index_page=get_page(index_url.format(i,))
        #解析主頁面,拿到視頻所在的地址列表
        detail_urls=parse_index(index_page)
        #循環(huán)爬取視頻頁
        for detail_url in detail_urls:
            #爬取視頻頁
            detail_page=get_page(detail_url)
            #拿到視頻的url
            movie_url=parse_detail(detail_page)
            if movie_url:
                #保存視頻
                save(movie_url)


if __name__ == '__main__':
    main()

并發(fā)爬取

from concurrent.futures import ThreadPoolExecutor
import queue
import requests
import re
import time
import hashlib
from threading import current_thread

p=ThreadPoolExecutor(50)

def get_page(url):
    print('%s GET %s' %(current_thread().getName(),url))
    try:
        response=requests.get(url)
        if response.status_code == 200:
            return response.content
    except Exception as e:
        print(e)

def parse_index(res):
    print('%s parse index ' %current_thread().getName())
    res=res.result()
    obj=re.compile('class="items.*?<a href="(.*?)"',re.S)
    detail_urls=obj.findall(res.decode('gbk'))
    for detail_url in detail_urls:
        if not detail_url.startswith('http'):
            detail_url='http://www.xiaohuar.com'+detail_url
        p.submit(get_page,detail_url).add_done_callback(parse_detail)

def parse_detail(res):
    print('%s parse detail ' %current_thread().getName())
    res=res.result()
    obj=re.compile('id="media".*?src="(.*?)"',re.S)
    res=obj.findall(res.decode('gbk'))
    if len(res) > 0:
        movie_url=res[0]
        print('MOVIE_URL: ',movie_url)
        with open('db.txt','a') as f:
            f.write('%s\n' %movie_url)
        # save(movie_url)
        p.submit(save,movie_url)
        print('%s下載任務(wù)已經(jīng)提交' %movie_url)
def save(movie_url):
    print('%s SAVE: %s' %(current_thread().getName(),movie_url))
    try:
        response=requests.get(movie_url,stream=False)
        if response.status_code == 200:
            m=hashlib.md5()
            m.update(('%s%s.mp4' %(movie_url,time.time())).encode('utf-8'))
            filename=m.hexdigest()
            with open(r'./movies/%s.mp4' %filename,'wb') as f:
                f.write(response.content)
                f.flush()
    except Exception as e:
        print(e)

def main():
    index_url='http://www.xiaohuar.com/list-3-{0}.html'
    for i in range(5):
        p.submit(get_page,index_url.format(i,)).add_done_callback(parse_index)


if __name__ == '__main__':
    main()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蚜印,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子留量,更是在濱河造成了極大的恐慌窄赋,老刑警劉巖哟冬,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異寝凌,居然都是意外死亡柒傻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門较木,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人青柄,你說我怎么就攤上這事伐债。” “怎么了致开?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵峰锁,是天一觀的道長。 經(jīng)常有香客問我双戳,道長虹蒋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任飒货,我火速辦了婚禮魄衅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘塘辅。我一直安慰自己晃虫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布扣墩。 她就那樣靜靜地躺著哲银,像睡著了一般。 火紅的嫁衣襯著肌膚如雪呻惕。 梳的紋絲不亂的頭發(fā)上荆责,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機(jī)與錄音亚脆,去河邊找鬼做院。 笑死,一個(gè)胖子當(dāng)著我的面吹牛型酥,可吹牛的內(nèi)容都是我干的山憨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼弥喉,長吁一口氣:“原來是場噩夢啊……” “哼郁竟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起由境,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤棚亩,失蹤者是張志新(化名)和其女友劉穎蓖议,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讥蟆,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勒虾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瘸彤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片修然。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖质况,靈堂內(nèi)的尸體忽然破棺而出愕宋,到底是詐尸還是另有隱情,我是刑警寧澤结榄,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布中贝,位于F島的核電站,受9級特大地震影響臼朗,放射性物質(zhì)發(fā)生泄漏邻寿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一视哑、第九天 我趴在偏房一處隱蔽的房頂上張望绣否。 院中可真熱鬧,春花似錦黎炉、人聲如沸枝秤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淀弹。三九已至,卻和暖如春庆械,著一層夾襖步出監(jiān)牢的瞬間薇溃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工缭乘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沐序,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓堕绩,卻偏偏與公主長得像策幼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子奴紧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353