requests庫使用方法(爬蟲模擬登陸的三種方式) = ̄ω ̄= Python爬蟲

requests

作用:發送網絡請求,返回相應數據 中文文檔API

requests使用

亂碼解決方式

文本亂碼

  1. 方法一
    使用.text方法讀取內容,使用.encoding修改編碼方式
		r = requests.get('http://www.baidu.com/')
        r.encoding = 'utf-8'
        print(r.text)
  1. 方法二
    使用.content方法讀取內容,使用.decode修改編碼方式
		r = requests.get('http://www.baidu.com/')
        print(r.content.decode('utf8'))

如果是圖片、視頻、音頻等內容直接使用.content方法讀取即可,如果使用decode方法修改編碼會報錯

僞裝瀏覽器

我們先來模仿瀏覽器獲取百度內容

  1. headers: 請求頭,User-Agent用於模擬瀏覽器(小知識:每個瀏覽器的信息中都有Mozilla,Mozilla是網景瀏覽器的內核,因爲一些歷史原因網景已經消失在歷史的長河中,但網景對瀏覽器發展的巨大影響尚未消失)
  2. get: 使用get請求獲取網站內容
  3. encoding:定義網站使用的編碼(國內常用utf-8,也可能使用gbk)
import requests
class ReptileTest:
    def __init__(self):
        self.request_header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
    def main(self):
        # 使用get方法連接百度
        r = requests.get('http://www.baidu.com', headers=self.request_header)
        # 定義編碼
        r.encoding = 'utf-8'
        # 輸出內容
        print(r.text)
if __name__ == '__main__':
    reptile = ReptileTest()
    reptile.main()

發送帶參請求

URL知識,URL中可以傳遞給服務器產生,參數一般是靈活多變的,有時候我們並不會直接將參數寫死,這時候我們可以將參數以字典的形式動態傳入。

import requests
# http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=50
class ReptileTest:
    def __init__(self):
        self.request_header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.3992.4 Safari/537.36'}
    def main(self):
        """主函數"""
        data = {
            'kw': 'python',
            'pn': 50
        }
        r = requests.get('http://tieba.baidu.com/f', headers=self.request_header, params=data)
        r.encoding = 'utf-8'
        print(r.text)
if __name__ == '__main__':
    reptile = ReptileTest()
    reptile.main()

實戰測試抓取

百度貼吧

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# @Author  : 尋覓
# @File    : requests庫入門.py
# @Time    : 2020/1/9 1:12
# @Software: PyCharm

import requests
# 抓取百度貼吧的Python論壇頁面
# http://tieba.baidu.com/f?kw=python&pn=50
# http://tieba.baidu.com/f?kw=python&pn=100


class ReptileTest:
    def __init__(self, name, page):
        self.request_url = 'http://tieba.baidu.com/f'
        self.request_header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
        self.name = {'kw': name, 'pn': 0}
        self.page = page

    def parse_url(self):
        """構造連接列表"""
        if (self.page-1)*50 > self.name['pn']:
            self.name['pn'] += 50
        else:
            self.page = False

    def save_html(self):
        """保存頁面"""
        r = requests.get('http://tieba.baidu.com/f', headers=self.request_header, params=self.name)
        r.encoding = 'utf-8'
        with open(f'{self.name["kw"]}貼吧第{self.name["pn"] // 50 + 1}頁.html', 'wb') as w:
            w.write(r.content)

    def run(self):
        """運行"""
        while self.page:
            self.save_html()
            self.parse_url()
if __name__ == '__main__':
    tieba_name = input('請輸入爬取貼吧的名稱')
    tieba_page = int(input('需要爬取的頁數'))
    reptile = ReptileTest(tieba_name, tieba_page)
    reptile.run()

胡蘿蔔周

class ReptileTest:
    def __init__(self, page):
        self.request_url = 'http://www.carrotchou.blog/page/{}'
        self.request_header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
        self.page = page
        self.cur = 1

    def parse_url(self):
        """構造連接列表"""
        if self.page > self.cur:
            self.cur += 1
        else:
            self.page = False

    def save_html(self):
        """保存頁面"""
        r = requests.get(self.request_url.format(self.cur), headers=self.request_header)
        r.encoding = 'utf-8'
        with open(f'胡蘿蔔周第{self.cur}頁.html', 'wb') as w:
            w.write(r.content)

    def run(self):
        """運行"""
        while self.page:
            self.save_html()
            self.parse_url()
if __name__ == '__main__':
    carrot_page = int(input('需要爬取的頁數'))
    reptile = ReptileTest(carrot_page)
    reptile.run()

帶參post請求

POST因爲其隱式傳輸(傳輸內容不會再URL中顯示),傳輸內容大小無限制等特性,常用於登陸註冊或者大文件傳輸時使用

有道翻譯

大多數網站的PC端反扒已經較爲完善,這時候我們可以嘗試對網站的手機端進行數據爬取,有道的PC端存在反扒措施,但是手機端可以直接爬取,下面我們就來嘗試使用有道翻譯進行post請求測試,有道翻譯手機版在2020年1月還未有反扒措施。
這裏首先我們使用.post方法請求,而不是.get方法請求,之後我們需要在請求中添加請求數據(data),這裏的數據也就是我們需要翻譯的內容。我們可以在瀏覽器控制檯中查看
在這裏插入圖片描述
將此時數據填入data中即可。進行帶參數的post訪問

import requests
# 使用post請求
class ReptileTest:
    def __init__(self):
        self.request_url = 'http://m.youdao.com/translate'
        self.request_header = {'User-Agent': 'Mozilla/5.0 (Linux; Android 7.0; SM-G892A Build/NRD90M; wv) '
                                             'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 '
                                             'Mobile Safari/537.36'}
        self.data = {"inputtext": "測試", "type": "AUTO"}

    def main(self):
        """主函數"""
        r = requests.post(self.request_url, data=self.data, headers=self.request_header)
        with open('翻譯.html', 'wb') as w:
            w.write(r.content)
if __name__ == '__main__':
    reptile = ReptileTest()
    reptile.main()

使用代理IP

代理的作用在這裏就不做贅述了,以防被和諧
用法:.get方法.post方法中添加proxies屬性
proxies(代理):字典映射協議到代理的URL。

class ReptileTest:
    def __init__(self):
        self.request_header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.3992.4 Safari/537.36'}

    def main(self):
        """主函數"""
	    # 我這裏使用的免費ip可能只有幾分鐘的存活時間
        proxies = {
            'http': 'http://220.135.165.38:8080'
        }
        r = requests.get('http://www.baidu.com/', headers=self.request_header, proxies=proxies)
        r.encoding = 'utf-8'
        print(r.text)

if __name__ == '__main__':
    reptile = ReptileTest()
    reptile.main()

cookie 與 session

cookie與session都是用於保存數據的,他們最大的區別是cookie是在本地,也就是用戶的客戶端中保存數據,而session則是在服務器中保存數據他們相比起來各有優劣。

  1. cookie將數據保存在本地,可以將用戶信息保存在本地,可以簡化用戶再次操作的流程,而且可以記錄一些用戶習慣,可以更好的服務於用戶,但是這樣的做法導致數據安全性較低,cookie中保存的密碼私鑰等重要信息容易遭到泄露,同時本地的cookie可以被有心之人利用,進行cookie欺詐等行爲,且保存數據只能小於4k,大多數瀏覽器也規定一個站點最多隻能保存20個cookie。
  2. session將數據保存在服務器,雖然解決了安全性問題,但是如果有大量用戶,session會佔用服務器大量資源,使服務器性能下降。

爬蟲利用cookie與session

帶上cookie,我們可以模擬登陸後的用戶,但是帶上cookie後我們如果過於頻繁的去訪問服務器,也容易暴露出我們是爬蟲,在Python中,下面的我們都將使用人人網做測試。

模擬登陸方法一

思路:我們可以利用resquests庫中的.session()方法來保持用戶的登陸狀態。

  1. 特點:
    1. 適用於cookie保存時效短,易失效的網站,可以及時獲取最新的cookie,
    2. 每次都要程序運行都要重新獲取新的cookie操作較爲麻煩。
  2. 思路
    1. 首先我們打開人人網,找到表單提交的地址,在控制檯中,我們很容易就找到人人網登陸表單的提交地址爲:http://www.renren.com/PLogin.do
      在這裏插入圖片描述

    2. 調用requests庫中的.session()方法

    3. 用使用過.session()方法的對象對登陸表單提交地址進行post請求提交登陸數據,進行登陸操作,在使用post請求登陸後,會自動將cookie保存

    4. 使用帶cookie的對象用get請求,這時候就可以正常訪問個人用戶界面了

class ReptileCookie:
    def __init__(self):
        # 調用session方法
        self.session = requests.session()
        # 人人網登陸地址
        self.request_url = 'http://www.renren.com/PLogin.do'
        # 人人網個人信息頁面(每個人的個人信息頁面都不同,這裏需要改成你自己的頁面才能看到效果)
        self.request_login = 'http://www.renren.com/973399342/profile'
        self.request_header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4029.0 Safari/537.36'}
        self.login_data = {
            'email': '登陸郵箱',
            'password': '登陸密碼'
        }

    def main(self):
        # 使用session方法後,用戶將處於持續登陸狀態
        self.session.post(self.request_url, data=self.login_data, headers=self.request_header)
        # 這時候的session對象中已經保存了登陸的cookie信息,可以訪問登陸後才能訪問的頁面
        data = self.session.get(self.request_login, headers=self.request_header)
        return data


if __name__ == '__main__':
    reptile = ReptileCookie()
    items = reptile.main()
    items.encoding = 'utf-8'
    with open('人人.html', 'wb') as w:
        w.write(items.content)

模擬登陸方法二

使用cookie直接登陸

  1. 特點:
    1. 適用於cookie保存時效長或有專門獲取cookie工具的情況下使用。
    2. 需要在cookie過期前拿到所以數據。
  2. 思路
    1. 這時候我們需要進入已經登陸後的人人網,然後在開發者工具中找到cookie,並放在請求頭中。
      在這裏插入圖片描述
    2. 使用get請求直接請求對應的頁面
class ReptileCookie:
    def __init__(self):
        self.requests_header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4029.0 Safari/537.36',
            'Cookie': '填寫你的cookie'
        }
        self.requests_url = 'http://www.renren.com/973399342/profile'

    def main(self):
        return requests.get(self.requests_url, headers=self.requests_header)


if __name__ == '__main__':
    data = ReptileCookie()
    html_data = data.main()
    html_data.encoding = 'utf-8'
    with open('人人網.html', 'wb') as w:
        w.write(html_data.content)

模擬登陸方法三

第三方法和第二種類似,只是我們將請求頭中的cookie取出,利用get或post中的cookie屬性將cookie單獨傳入,但需要注意的是,這裏的cookie屬性只支持字典.
data = {i.split('=')[0]: i.split('=')[1] for i in cookie.split(';')}使用此字典推導式可以將方法二中的cookie轉換爲字典

class ReptileCookie:
    def __init__(self):
        self.requests_header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4029.0 Safari/537.36'}
        self.requests_cookie = {dict格式的cookie}
        self.requests_url = 'http://www.renren.com/973399342/profile'

    def main(self):
        return requests.get(self.requests_url, cookies=self.requests_cookie, headers=self.requests_header)


if __name__ == '__main__':
    items = ReptileCookie()
    data = items.main()
    data.encoding = 'utf-8'
    with open('人人網.html', 'wb') as w:
        w.write(data.content)

requests小技巧

將cookie對象轉化爲字典

上述模擬登陸時,我們多次使用了cookie,我們可以使用,requests庫中的.utils.dict_from_cookiejar()方法將cookie對象轉化爲字典,使用.utils.cookiejar_from_dict()方法在將字典轉化爲cookie對象。

import requests


class RequestsTest:
    def __init__(self):
        self.baidu_url = 'http://www.baidu.com'
        self.header = 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0'

    def geturl(self):
        demo = requests.get(self.baidu_url, self.header)
        # 將cookie對象轉化成字典的方法
        dic = requests.utils.dict_from_cookiejar(demo.cookies)
        # 將字典轉化爲cookie對象
        items = requests.utils.cookiejar_from_dict(dic)
        print(demo.cookies, dic, items)

    def main(self):
        """主函數"""
        self.geturl()


if __name__ == '__main__':
    RequestsTest().main()

判斷是否請求超時以及設置超時

當以及完成get或者post請求後,我們可以使用.status_code屬性查看連接狀態,如果是200即爲成功。
get和post請求中有一個timeout屬性可以設置超時(單位:秒),一旦超過指定時間就會報錯。

import requests


class RequestsTest:
    def __init__(self):
        self.baidu_url = 'http://www.baidu.com'
        self.google_url = 'http://www.google.com'
        self.header = 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0'

    def geturl(self, url):
        """判斷是否成功連接"""
        try:
            # 使用timeout方法連接
            demo = requests.get(url, self.header, timeout=1)
        # 如果超時就報超時錯誤
        except requests.exceptions.ConnectTimeout:
            data = '連接超時'
        # 其他錯誤則返回錯誤
        except Exception as e:
            data = e
        else:
            data = demo.status_code
        finally:
            # 判斷是否連接失敗
            if data == 200:
                demo.encoding = 'utf-8'
                return True, demo
            else:
                data = str(data)
                return False, f'連接出現錯誤,錯誤信息爲:{data}'

    def main(self):
        """主函數"""
        item = self.geturl(self.google_url)
        if item[0]:
            print(item[1].text)
        else:
            print(item[1])


if __name__ == '__main__':
    RequestsTest().main()

url中的中文的編碼與解碼

在這裏插入圖片描述
在url中的中文需要對其編碼和解碼才能正常看到(當下大多數瀏覽器都會自動進行編碼以及解碼)在Python中也提供了手動編碼以及解碼的方法,使用requests.utils.quote()方法編碼,使用requests.utils.unquote()方法解碼。

        # 編碼
        print(requests.utils.quote('尋覓'))
        # 解碼
        print(requests.utils.unquote('%E5%AF%BB%E8%A7%85'))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章