爬蟲基本原理

一 爬蟲是什麼

#一、什麼是互聯網?
    互聯網是由網絡設備(網線,路由器,交換機,防火牆等等)和一臺臺計算機鏈接而成,像一張網同樣。

#二、互聯網創建的目的?
    互聯網的核心價值在於數據的共享/傳遞:數據是存放於一臺臺計算機上的,而將計算機互聯到一塊兒的目的就是爲了可以方便彼此之間的數據共享/傳遞,不然你只能拿U盤去別人的計算機上拷貝數據了。

#三、什麼是上網?爬蟲要作的是什麼?
    咱們所謂的上網即是由用戶端計算機發送請求給目標計算機,將目標計算機的數據下載到本地的過程。
    #3.1 只不過,用戶獲取網絡數據的方式是:
      瀏覽器提交請求->下載網頁代碼->解析/渲染成頁面。

    #3.2 而爬蟲程序要作的就是:
      模擬瀏覽器發送請求->下載網頁代碼->只提取有用的數據->存放於數據庫或文件中
 
    #3.1與3.2的區別在於:
      咱們的爬蟲程序只提取網頁代碼中對咱們有用的數據

#四、總結爬蟲
    #4.1 爬蟲的比喻:
      若是咱們把互聯網比做一張大的蜘蛛網,那一臺計算機上的數據即是蜘蛛網上的一個獵物,而爬蟲程序就是一隻小蜘蛛,沿着蜘蛛網抓取本身想要的獵物/數據

    #4.2 爬蟲的定義:
      向網站發起請求,獲取資源後分析並提取有用數據的程序 

二 爬蟲的基本流程

#一、發起請求
使用http庫向目標站點發起請求,即發送一個Request
Request包含:請求頭、請求體等

#二、獲取響應內容
若是服務器能正常響應,則會獲得一個Response
Response包含:html,json,圖片,視頻等

#三、解析內容
解析html數據:正則表達式,第三方解析庫如Beautifulsoup,pyquery等
解析json數據:json模塊
解析二進制數據:以b的方式寫入文件

#四、保存數據
數據庫
文件

須要關注的點html

Request

#一、請求方式:
    經常使用的請求方式:GET,POST
    其餘請求方式:HEAD,PUT,DELETE,OPTHONS

    ps:用瀏覽器演示get與post的區別,(用登陸演示post)

    post與get請求最終都會拼接成這種形式:k1=xxx&k2=yyy&k3=zzz
    post請求的參數放在請求體內:
        可用瀏覽器查看,存放於form data內
    get請求的參數直接放在url後

#二、請求url
    url全稱統一資源定位符,如一個網頁文檔,一張圖片
    一個視頻等均可以用url惟一來肯定

    url編碼
    https://www.baidu.com/s?wd=圖片
    圖片會被編碼(看示例代碼)


    網頁的加載過程是:
    加載一個網頁,一般都是先加載document文檔,
    在解析document文檔的時候,遇到連接,則針對超連接發起下載圖片的請求

#三、請求頭
    User-agent:請求頭中若是沒有user-agent客戶端配置,
    服務端可能將你當作一個非法用戶
    host
    cookies:cookie用來保存登陸信息

    通常作爬蟲都會加上請求頭


#四、請求體
    若是是get方式,請求體沒有內容
    若是是post方式,請求體是format data

    ps:
    1、登陸窗口,文件上傳等,信息都會被附加到請求體內
    二、登陸,輸入錯誤的用戶名密碼,而後提交,就能夠看到post,正確登陸後頁面一般會跳轉,沒法捕捉到post 
def test3(content):
    with open("a.html", "w", encoding="utf-8") as f:
        f.write(content)


def test2():
    keyword = input("搜索關鍵詞>>:").strip()
    page = input("搜索第幾頁>>:").strip()
    url = "https://www.baidu.com/s?"
    response = requests.get(
        url,
        params={
            "wd": keyword,
            "pn": (int(page)-1) * 10
        },
        headers={
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36'
        }
    )
    test3(response.text)


if __name__ == '__main__':
    test2()
模擬百度搜索

Response

#一、響應狀態
    200:表明成功
    301:表明跳轉
    404:文件不存在
    403:權限
    502:服務器錯誤

#二、Respone header
    set-cookie:可能有多個,是來告訴瀏覽器,把cookie保存下來
    
#三、preview就是網頁源代碼
    最主要的部分,包含了請求資源的內容
    如網頁html,圖片
    二進制數據等

總結

#一、總結爬蟲流程:
    爬取--->解析--->存儲

#二、爬蟲所需工具:
    請求庫:requests,selenium
    解析庫:正則,beautifulsoup,pyquery
    存儲庫:文件,MySQL,Mongodb,Redis

#三、爬蟲經常使用框架:
    scrapy
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)
        #循環爬取視頻頁
        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()


#併發爬取
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下載任務已經提交' %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()
爬取校花網視頻
相關文章
相關標籤/搜索