天天看點

python學習筆記-爬蟲01

#============================爬蟲準備工作============================

# 參考資料

    # python網絡資料采集, 圖靈工業出版

    # 精通Python爬蟲架構Scrapy, 人民郵電出版社

    # [Python3網絡爬蟲](http://blog.csdn.net/c406495762/article/details/72858983)

    # [Scrapy官方教程](http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html)

# 前提知識

    # url

    # http協定

    # web前端,html, css, js

    # ajax

    # re, xpath

    # xml

#============================爬蟲簡介============================

# 爬蟲定義:網絡爬蟲(又被稱為網頁蜘蛛,網絡機器人,在FOAF社群中間,更經常的稱為網頁追逐者),

        #是一種按照一定的規則,自動地抓取網際網路資訊的程式或者腳本。

        #另外一些不常使用的名字還有螞蟻、自動索引、模拟程式或者蠕蟲。

# 兩大特征

    # 能按作者要求下載下傳資料或者内容

    # 能自動在網絡上流竄

# 三大步驟:

    # 下載下傳網頁

    # 提取正确的資訊

    # 根據一定規則自動跳到另外的網頁上執行上兩步内容

# 爬蟲分類

    # 通用爬蟲

    # 專用爬蟲(聚焦爬蟲)

# Python網絡包簡介

    # Python2.x:urllib, urllib2, urllib3, httplib, httplib2, requests

    # Python3.x: urllib, urllib3, httplib2, requests

    # python2: urllib和urllib2配合使用,或者requests

    # Python3: urllib,requests

#==========================urllib=========================

# 包含子產品

    # urllib.request: 打開和讀取urls

    # urllib.error: 包含urllib.request産生的常見的錯誤,使用try捕捉

    # urllib.parse:  包含解析url的方法

    # urllib.robotparse: 解析robots.txt檔案

    # 案例v1:

    from urllib import request
    url = "http://jobs.zhaopin.com/..."
    # 打開相應url并把相應頁面作為傳回
    rsp = request.urlopen(url)
    # 把傳回結果讀取出來
    # 讀取出來内容類型為bytes
    html = rsp.read()
    # 如果想把bytes内容轉換成字元串,需要解碼
    html = html.decode("utf-8")
           

# 網頁編碼問題解決

    # chardet 可以自動檢測頁面檔案的編碼格式,但是,可能有誤

    # 需要安裝, conda install chardet

    # 案例v2片段:

    #利用 chardet自動檢測
    cs = chardet.detect(html)
    # 使用get取值保證不會出錯
    html = html.decode(cs.get("encoding", "utf-8"))
           

# urlopen 的傳回對象

    # geturl: 傳回請求對象的url

    # info: 請求回報對象的meta資訊

    # getcode:傳回的http code    

# request.data 的使用

    # 通路網絡的兩種方法

        # get: 

            # 利用參數給伺服器傳遞資訊,

            # 參數為dict,然後用parse編碼

            # 案例v4片段:

from urllib import request, parse

url = 'http://www.baidu.com/s?'
wd = input("Input your keyword:")

# 要想使用data, 需要使用字典結構
qs = {"wd": wd}
# 轉換url編碼
qs = parse.urlencode(qs)
fullurl = url + qs
# 如果直接用可讀的帶參數的url,是不能通路的
#fullurl = 'http://www.baidu.com/s?wd=大熊貓'
rsp = request.urlopen(fullurl)
html = rsp.read()
           

        # post

            # 一般向伺服器傳遞參數使用

            # post是把資訊自動加密處理

            # 我們如果想使用post資訊,需要用到data參數

            # 使用post,意味着Http的請求頭可能需要更改:

                # Content-Type: application/x-www.form-urlencode

                # Content-ength: 資料長度

                # 簡而言之,一旦更改請求方法,請注意其他請求頭部資訊相适應

            # urllib.parse.urlencode可以将字元串自動轉換成上面的

            # 案例v5:經典案例:

'''
利用parse子產品模拟post請求
分析百度詞典
分析步驟:
1. 打開F12
2. 嘗試輸入單詞girl,發現每敲一個字母後都有請求
3. 請求位址是 http://fanyi.baidu.com/sug
4. 利用NetWork-All-Hearders,檢視,發現FormData的值是 kw:girl
5. 檢查傳回内容格式,發現傳回的是json格式内容==>需要用到json包
'''
from urllib import request, parse
# 負責處理json格式的子產品
import json
'''
大緻流程是:
1. 利用data構造内容,然後urlopen打開
2. 傳回一個json格式的結果
3. 結果就應該是girl的釋義
'''
baseurl = 'http://fanyi.baidu.com/sug'
# 存放用來模拟form的資料一定是dict格式
data = {
    # girl是翻譯輸入的英文内容,應該是由使用者輸入,此處使用寫死
    'kw': 'girl'
}
# 需要使用parse子產品對data進行編碼
data = parse.urlencode(data).encode("utf-8")
rsp = request.urlopen(baseurl, data=data)
json_data = rsp.read().decode('utf-8')
# 把json字元串轉化成字典
json_data = json.loads(json_data)
print(type(json_data))
print(json_data)
for item in json_data['data']:
    print(item['k'], "--", item['v'])
           

            # 為了更多的設定請求資訊,單純的通過urlopen函數已經不太好用了

            # 需要利用request.Request 類

                        # 構造一個Request的執行個體

                        # 我們需要構造一個請求頭,請求頭部應該至少包含傳入的資料的長度

                        # request要求傳入的請求頭是一個dict格式

                        headers = {

                            # 因為使用post,至少應該包含content-length 字段

                            'Content-Length':len(data)

                        }

                        # 有了headers,data,url,就可以嘗試送出請求了

                        req = request.Request(url=baseurl, data=data, headers=headers)

                        # 因為已經構造了一個Request的請求執行個體,則所有的請求資訊都可以封裝在Request執行個體中

                        rsp = request.urlopen(req)

# urllib.error

    # URLError産生的原因:

        # 沒網

        # 伺服器連結失敗

        # 知不道制定伺服器

        # 是OSError的子類

    # HTTPError, 是URLError的一個子類

        # 案例v8      

from urllib import request, error
try:
    req = request.Request(url)
    rsp = request.urlopen(req)
    html = rsp.read().decode()
    print(html)
except error.HTTPError as e:
    print("HTTPError: {0}".format(e.reason))
    print("HTTPError: {0}".format(e))
except error.URLError as e:
    print("URLError: {0}".format(e.reason))
    print("URLError: {0}".format(e))
except Exception as e:
    print(e)
           

    # 兩者差別:

        # HTTPError是對應的HTTP請求的傳回碼錯誤, 如果傳回錯誤碼是400以上的,則引發HTTPError

        # URLError對應的一般是網絡出現問題,包括url問題

        # 關系差別: OSError-URLError-HTTPError

# UserAgent 

    # UserAgent: 使用者代理,簡稱UA, 屬于heads的一部分,伺服器通過UA來判斷通路者身份

    # 常見的UA值,使用的時候可以直接複制粘貼,也可以用浏覽器通路的時候抓包

            1.Android

            Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19

            Mozilla/5.0 (Linux; U; Android 4.0.4; en#gb; GT#I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30

            Mozilla/5.0 (Linux; U; Android 2.2; en#gb; GT#P1000 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1

            2.Firefox

            Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0

            Mozilla/5.0 (Android; Mobile; rv:14.0) Gecko/14.0 Firefox/14.0

            3.Google Chrome

            Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36

            Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19

            4.iOS

            Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3

            Mozilla/5.0 (iPod; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3A101a Safari/419.3

    # 設定UA可以通過兩種方式:

        # heads

        # add_header

        # 使用head方法僞裝UA

        # headers = {}

        # headers['User-Agent'] = 'Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3'

        # req = request.Request( url, headers=headers)

        # 使用add_header方法

        req = request.Request(url)

        req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36")

        # 正常通路

        rsp = request.urlopen( req )

        html = rsp.read().decode()

        print(html)

# ProxyHandler處理(代理伺服器)

    # 使用代理IP,是爬蟲的常用手段

    # 擷取代理伺服器的位址:

        # www.xicidaili.com

        # www.goubanjia.com

    # 代理用來隐藏真實通路中,代理也不允許頻繁通路某一個固定網站,是以,代理一定要很多很多

    # 基本使用步驟:

    from urllib import  request, error
    url = "http://www.baidu.com"
    # 使用代理步驟
    # 1. 設定代理位址
    proxy = {'http': '120.194.18.90:81' }
    # 2. 建立ProxyHandler
    proxy_handler = request.ProxyHandler(proxy)
    # 3. 建立Opener
    opener = request.build_opener(proxy_handler)
    # 4. 安裝Opener
    request.install_opener(opener)
    # 現在如果通路url,則使用代理伺服器
    try:
        rsp = request.urlopen(url)
        html = rsp.read().decode()
        print(html)
    except error.URLError as e:
        print(e)
    except Exception as e:
        print(e)
           

# cookie & session

    # 由于http協定的無記憶性,人們為了彌補這個缺憾,所采用的一個補充協定

    # cookie是發放給使用者(即http浏覽器)的一段資訊,session是儲存在伺服器上的對應的另一半資訊,用來記錄使用者資訊

# cookie和session的差別

    # 存放位置不同

    # cookie不安全

    # session會儲存在伺服器上一定時間,會過期

    # 單個cookie儲存資料不超過4k, 很多浏覽器限制一個站點最多儲存20個

# session的存放位置

    # 存在伺服器端

    # 一般情況,session是放在記憶體中或者資料庫中

    # 沒有cookie登入,回報網頁為未登入狀态

# 使用cookie登入

    # 直接把cookie複制下來,然後手動放入請求頭:

    headers = {

        "Cookie": "xxxx"

    }

    req = request.Request(url, headers=headers)

    # http子產品包含一些關于cookie的子產品,通過他們我們可以自動使用cookie

        # CookieJar

            # 管理存儲cookie,向傳出的http請求添加cookie,

            # cookie存儲在記憶體中,CookieJar執行個體回收後cookie将消失

        # FileCookieJar(filename, delayload=None, policy=None):

            # 使用檔案管理cookie

            # filename是儲存cookie的檔案

        # MozillaCookieJar(filename, delayload=None, policy=None):

            # 建立與mozilla浏覽器cookie.txt相容的FileCookieJar執行個體

        # LwpCookieJar(filename, delayload=None, policy=None):

            # 建立與libwww-perl标準相容的Set-Cookie3格式的FileCookieJar執行個體

        # 他們的關系是: CookieJar-->FileCookieJar-->MozillaCookieJar & LwpCookieJar

    # handler是Handler的執行個體

        # 用來處理複雜請求 

    # 創立handler後,使用opener打開,打開後相應的業務由相應的hanlder處理

    # cookie的儲存-FileCookieJar

        cookie.save(ignore_discard=True, ignore_expires=True)

    # cookie的讀取:

        cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)

    # 案例:利用cookiejar通路網站

# 自動使用cookie登入,大緻流程是
# 打開登入頁面後自動通過使用者名密碼登入
# 自動提取回報回來的cookie
# 利用提取的cookie登入隐私頁面    

from urllib import request, parse
from http import cookiejar

# 建立cookiejar的執行個體
# cookie = cookiejar.CookieJar()
# 需要儲存成文本時建立MozillaCookieJar或FileCookieJar的執行個體
filename = "cookie.txt"
cookie = cookiejar.MozillaCookieJar(filename)
# cookie的讀取:
# cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)
# 生成 cookie的管理器
cookie_handler = request.HTTPCookieProcessor(cookie)
# 建立http請求管理器
http_handler = request.HTTPHandler()
# 生成https管理器
https_handler = request.HTTPSHandler()
# 建立請求管理器
opener = request.build_opener(http_handler, https_handler, cookie_handler)
def login():
    '''
    負責初次登入
    需要輸入使用者名密碼,用來擷取登入cookie憑證
    :return:
    '''
    # 此url需要從登入form的action屬性中提取
    url = "http://www.renren.com/PLogin.do"
    # 此鍵值需要從登入form的兩個對應input中提取name屬性
    data = {
        "email": "13119144223",
        "password": "123456"
    }
    # 把資料進行編碼
    data = parse.urlencode(data)
    # 建立一個請求對象
    req = request.Request(url, data=data.encode())
    # 使用opener發起請求
    rsp = opener.open(req)
    
    # 儲存cookie到檔案
    # ignor_discard表示即使cookie将要被丢棄也要儲存下來
    # ignore_expire表示如果該檔案中cookie即使已經過期,儲存
    cookie.save(ignore_discard=True, ignore_expires=True)
    
def getHomePage():
    url = "http://www.renren.com/965187997/profile"
    # 如果已經執行了login函數,則opener自動已經包含相應的cookie值
    rsp = opener.open(url)
    html = rsp.read().decode()
   
if __name__ == '__main__':
    login()
    getHomePage()
           

    # cookie作為一個變量,列印出來, 案例片段:

    print(cookie)
    for item in cookie:
        print(type(item))
        print(item)
        for i in dir(item):
            print(i)
           

    # cookie的屬性

        # name: 名稱

        # value: 值

        # domain:可以通路此cookie的域名

        # path: 可以通路此cookie的頁面路徑

        # expires:過期時間

        # size: 大小

        # Http字段

# SSL

    # SSL證書就是指遵守SSL安全套階層協定的伺服器數字證書(SercureSocketLayer)

    # 美國網景公司開發

    # CA(CertifacateAuthority)是數字證書認證中心,是發放,管理,廢除數字證書的收信人的第三方機構

    # 遇到不信任的SSL證書,需要單獨處理,案例:

# 導入pythopn ssl處理子產品
import ssl

# 利用非認證上下文環境替換認證的向下文環境
ssl._create_default_https_context = ssl._create_unverified_context
url = "https://www.12306.cn/mormhweb/"
rsp = request.urlopen(url)
html = rsp.read().decode()
           

# js加密

    # 有的反爬蟲政策采用js對需要傳輸的資料進行加密處理(通常是取md5值)

    # 經過加密,傳輸的就是密文,但是

    # 加密函數或者過程一定是在浏覽器完成,也就是一定會把代碼(js代碼)暴露給使用者

    # 通過閱讀加密算法,就可以模拟出加密過程,進而達到破解

    # 過程參看案例v19

    # 注意salt,sign的計算

# ajax

    # 異步請求

    # 一定會有url,請求方法,可能有資料

    # 一般使用json格式

    # 案例,爬去豆瓣電影, 案例v20

    # 注意請求值

#================================Requests==========================

# HTTP for Humans,更簡潔更友好

# 繼承了urllib的所有特征

# 底層使用的是urllib3

# 開源位址: https://github.com/requests/requests

# 中文文檔: http://docs.python#requests.org/zh_CN/latest/index.html   

# 安裝: conda install requests

# get請求

    # requests.get(url)

    # requests.request("get", url)

    # 可以帶有headers和parmas參數

import requests

url = "http://www.baidu.com"
# 兩種請求方式
# 使用get請求
rsp = requests.get(url)
print(rsp.text)

# 使用request請求
rsp = requests.request("get", url, params=kw, headers=headers)
print(rsp.text)

# get傳回内容
print(rsp.text)
print(rsp.content)
print(rsp.url)
print(rsp.encoding)
print(rsp.status_code) # 請求傳回碼
           

    # post

rsp = requests.post(baseurl, data=data,  headers=headers)
           

    # date, headers要求dict類型,不需要編碼成byte流

   # proxy

   # 

proxies = {
"http":"address of proxy",
"https": "address of proxy"
}
rsp = requests.request("get", "http:xxxxxx", proxies=proxies)
           

# 代理有可能報錯,如果使用人數多,考慮安全問題,可能會被強行關閉

# 使用者驗證

    # 代理驗證

#可能需要使用HTTP basic Auth, 可以這樣
# 格式為  使用者名:密碼@代理位址:端口位址
proxy = { "http": "china:[email protected]:4444"}
rsp = requests.get("http://baidu.com", proxies=proxy)
           

# web用戶端驗證

    # 如果遇到web用戶端驗證,需要添加auth=(使用者名,密碼)

autu=("test1", "123456")#授權資訊
rsp = requests.get("http://www.baidu.com", auth=auth)
           

# cookie

# requests可以自動處理cookie資訊
rsp = requests.get("http://xxxxxxxxxxx")
# 如果對方伺服器給傳送過來cookie資訊,則可以通過回報的cookie屬性得到
# 傳回一個cookiejar執行個體
cookiejar = rsp.cookies   
#可以講cookiejar轉換成字典
cookiedict = requests.utils.dict_from_cookiejar(cookiejar)         
           

# session

    # 跟伺服器端session不是一個東東

    # 模拟一次會話,從用戶端浏覽器連結伺服器開始,到用戶端浏覽器斷開

    # 能讓我們跨請求時保持某些參數,比如在同一個session執行個體發出的 所有請求之間保持cookie

# 建立session對象,可以保持cookie值
ss = requests.session()
headers = {"User-Agent":"xxxxxxxxxxxxxxxxxx"}
data = {"name":"xxxxxxxxxxx"}
# 此時,由建立的session管理請求,負責送出請求,
ss.post("http://www.baidu.com", data=data, headers=headers)
rsp = ss.get("xxxxxxxxxxxx")
           

# https請求驗證ssl證書

    # 參數verify負責表示是否需要驗證ssL證書,預設是True

    # 如果不需要驗證ssl證書,則設定成False表示關閉

    # 如果用verify=True通路12306,會報錯,因為他證書有問題 

rsp = requests.get("https://www.baidu.com", verify=False)