爬蟲學習(一)

先來複習複習字符串的編碼方式

字符串複習

字符串符合兩種類型

  • byte:二進制
    互聯網上數據的都是以二進制的方式傳輸的
  • str:unicode的呈現方式

兩者是可以相互轉換的,但必須編碼解碼方式一樣,否則就會出錯

str使用encode方法轉化爲bytes

bytes通過decode轉化成str

a = '你好,爬蟲'
print(type(a))

b = a.encode()
print(type(b))
print(b)

在這裏插入圖片描述
還可以加上編碼解碼方式

b = a.encode("UTF-8")

後續如果爬蟲網頁源代碼出現亂碼,可能就是編碼方式不一致

那麼正題要開始了

requests使用入門

如何請求頁面,並獲取頁面的內容

import requests

# 請求網頁
r = requests.get("http://www.baidu.com")

# r是一個response對象,我們想到得到的信息都可以從它獲取
print(r)

# 得到r的內容
print(r.text)

如果打印r.text出現亂碼,則可以先指定編碼方式,再打印看看

# 指定編碼方式
r.encoding = 'utf-8'
print(r.text)

還有一種方法可以獲取網頁的內容

那就是r.content

但它是二進制形式打印出來

需要解碼,可以指定編碼方式(默認是utf-8),例如gbk,gb2312

r.content.decode()

更推薦這種方式獲取網頁內容

動動手-保存圖片到本地

不僅圖片,mp4,gif,pdf等常見的格式文件都可以這樣做

import requests

# 圖片地址
page_url = 'https://i0.hdslb.com/bfs/archive/cb110cffbf66ae37169e1b8bca68d138a9de97e5.png@880w_440h.png'

# 發送get請求
r = requests.get(page_url)

# 保存,寫入二進制文件
with open('a.png','wb') as f:
    f.write(r.content)

獲取更多的數據

  • response.status_code 狀態碼,當爲200的時候請求某一個url成功,並不一定是訪問我們想要的url成功,因爲登入的時候網頁有重定向
  • response.request.url 請求的url

發送帶headers的請求

爲什麼要發送帶headers的請求?

發送帶headers的請求的目的就爲了模仿瀏覽器訪問網頁,欺騙服務器,獲取和瀏覽器一致的內容

那headers從何而來呢?

在瀏覽器上面,按F12,點擊network
在這裏插入圖片描述
最常用的是User-Agent

import requests

# 請求頭
headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0"
}

# 發送get請求,帶請求頭
r = requests.get("http://www.baidu.com",headers=headers)

# 打印內容
print(r.content.decode())

發送帶參數的請求

什麼是參數?

比如這個url

https://www.baidu.com/s?wd=python&c=b

後面以 & 分開的都是參數

那麼這個可不可以去掉呢?

我們來嘗試嘗試

先不去試試看

import requests

# 請求頭
headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0"
}

# 參數
p = {"wd":"python"}

# 發送get請求,帶請求頭, 帶參數
r = requests.get("http://www.baidu.com/s?",headers=headers,params=p)

# 打印狀態碼
print(r.status_code)

# 打印請求的url
print(r.request.url)

可以請求成功
在這裏插入圖片描述

去掉看看

import requests

# 請求頭
headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0"
}

# 參數
p = {"wd":"python"}

# 發送get請求,帶請求頭, 帶參數
r = requests.get("http://www.baidu.com/s",headers=headers,params=p)

# 打印狀態碼
print(r.status_code)

# 打印請求的url
print(r.request.url)

發現是一樣的
在這裏插入圖片描述

如果不確定的話,可以用字符串拼接

# 發送get請求,帶請求頭, 帶參數
url = "http://www.baidu.com/s?{}".format("python")
r = requests.get(url,headers=headers,params=p)

動動手-任意貼吧的爬蟲

想要實現任意貼吧的爬取,就要分析url的規律

例如 https://tieba.baidu.com/f?kw=李毅

kw後面的值爲什麼,就是什麼吧

然後我們想爬取這個貼吧的1000頁頁面的內容

1000頁!這也得要找出規律

當我們點擊下一頁的時候,url發生了這樣的變化

https://tieba.baidu.com/f?kw=李毅&pn=50,後面多了個pn=50

繼續點擊下一頁,發現每點擊下一頁,pn就多加50

pn=0,當令它爲0,發現就爲第一頁,於是就是這麼個規律

我們定義一個貼吧類

import requests

class TiebaSpider:
    def __init__(self,tieba_name):
        self.tieba_name = tieba_name
        self.url = "https://tieba.baidu.com/f?kw="+tieba_name+"&ie=utf-8&pn={}"
        self.headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0"}

    def get_url_list(self):
        url_list = []
        for i in range(1000):
            url_list.append(self.url.format(i*50))
        return url_list

    def parse_url(self,url): #發送請求,獲取響應
        print(url)
        r = requests.get(url,headers=self.headers)
        return r.content.decode()

    def save_html(self,html_str,page_num): # 保存html字符串
        file_path = "{}-第{}頁.html".format(self.tieba_name,page_num)
        with open(file_path,"w") as f:
            f.write(html_str)

    def run(self): #實現主要邏輯
        # 1.構造url列表
        url_list = self.get_url_list()
        # 2.遍歷,發送請求,獲取響應
        for url in url_list:
            html_str = self.parse_url(url)
            # 3.保存
            page_num = url_list.index(url) + 1
            self.save_html(html_str,page_num)


if __name__ == '__main__':
    tieba_spider = TiebaSpider("李毅")
    tieba_spider.run()

當我們運行的時候卻出錯了

看看提示什麼錯誤

在這裏插入圖片描述
似乎是編碼問題

其實是寫入文件的編碼方式不對

改改這裏就行了,加一個編碼方式寫入文件

    def save_html(self,html_str,page_num): # 保存html字符串
        file_path = "{}-第{}頁.html".format(self.tieba_name,page_num)
        with open(file_path,"w",encoding="utf-8") as f:
            f.write(html_str)

在來運行運行,發現可以用了(中途終止了程序)
在這裏插入圖片描述

既然是任意貼吧的爬蟲,我們來試試爬取別的,看看能不能看到效果

比如爬取lol的頁面

只要實例化時傳入相應的參數就行

if __name__ == '__main__':
    tieba_spider = TiebaSpider("lol")
    tieba_spider.run()

來看看結果

發現是可以用的

在這裏插入圖片描述
那麼程序就寫完了

這段程序裏面的run方法主要實現邏輯,更好的可以方便觀察,提高編程技巧

其實有個地方可以寫的更簡單

    def get_url_list(self):
        url_list = []
        for i in range(1000):
            url_list.append(self.url.format(i*50))
        return url_list

可以改成這樣的,一句就可以解決

    def get_url_list(self):
        # url_list = []
        # for i in range(1000):
        #     url_list.append(self.url.format(i*50))
        # return url_list
        return [self.url.formate(i*50) for i in range(1000)]

發送post請求

一些地方我們會使用post請求

  • 登入註冊(postget更安全)
  • 需要傳輸大文本內容的時候(post請求對數據長度沒有要求)

相對與get請求多了一個data

r = requests.pot(url,data=data,headers=headers)

百度翻譯就是一個典型的post請求,因爲翻譯時候往往是輸入很多內容,我們來抓包,來獲取百度翻譯的posturl和postdata

這很簡單,一個一個往下找就是了 ~ _ ~

我們需要找到post的url,和需要post的數據

需要點擊翻譯按鈕,然後進行抓包,點擊翻譯按鈕相當於發送了一次post請求

在這裏插入圖片描述

雖然這data裏面的內容後面幾個還不清楚是什麼意思,我們可以寫如下程序,來檢測一下

import requests

headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0"}

data={
    "from": "zh",
    "to": "en",
    "query": "你好",
    "transtype": "translang",
    "simple_means_flag": "3",
    "sign": "232427.485594",
    "token": "8e3e547a6eeb51b0e15dadf70e7e01f0"
}
post_url = "https://fanyi.baidu.com/v2transapi"

r = requests.post(post_url,data=data,headers=headers)
print(r)

在這裏插入圖片描述

打印後發現狀態碼是200,但是200只是意味着我們請求某一個url成功,並不代表請求我們想要的url成功,因爲可能網頁有跳轉

我們再打印內容看看

print(r.content.decode())

在這裏插入圖片描述

發現並沒有得到我們想要得數據

到底是什麼原因導致我們拿不到我們想要得數據?

有兩點問題

第一,headers不全,可能需要加入更多得鍵值對

第二,是data裏面得鍵值對,是不是都需要,還是要不要某個鍵值對要變,不是固定值

其實問題是出在第二點

我們也不知道哪個鍵值對需不需要,哪個鍵值對變不變化

我們可以換一個方式

不用和它正面槓,我們可以使用手機版得百度翻譯,繞行方法

我們需要再來看看手機版的,進行再一次抓包

點擊這個切換到,手機模式

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章