爬蟲初識和request使用


一.什么是爬蟲

  爬蟲的概念:

通過編寫程序,模擬瀏覽器上網,讓其去互聯網上爬取數據的過程.

  爬蟲的工作流程:

 模擬瀏覽器發送請求->下載網頁代碼->只提取有用的數據->存放於數據庫或文件中

  
  

  爬蟲的分類:

  • 通用爬蟲:爬取全部的頁面數據.
  • 聚焦爬蟲: 抓取頁面中局部的頁面數據
  • 增量式爬蟲:爬取網站中更新出的數據

  反爬機制

門戶網站會通過制定相關的技術手段阻止爬蟲程序進行數據的爬取  

  反反爬策略:

  • robots.txt協議: 防君子不防小人的協議
  • UA檢測 ----->用戶表示(通過什么樣的代理發起的請求)
  • cookie ------>訪問記錄
  • 驗證碼 ------>打碼平台
  • 動態加載數 ---->捕獲ajax包
  • reference ---->跳轉過來的地址

二.requests模塊

  1.requests請求過程涉及的協議

#1、請求方式:
    常用的請求方式:
    GET:請求數據
    POST:提交數據
    PUT:更新數據
DELETE:刪除數據 post與get請求最終都會拼接成這種形式:k1
=xxx&k2=yyy&k3=zzz
post請求的參數放在請求體內: 可用瀏覽器查看,存放於form data內 get請求的參數直接放在url后
#2、請求url url全稱統一資源定位符,如一個網頁文檔,一張圖片 一個視頻等都可以用url唯一來確定 url編碼 https://www.baidu.com/s?wd=圖片 圖片會被編碼(看示例代碼) 網頁的加載過程是: 加載一個網頁,通常都是先加載document文檔, 在解析document文檔的時候,遇到鏈接,則針對超鏈接發起下載圖片的請求
#3、請求協議格式:

  請求首行:
    協議格式:HTTP/HTTPS
    請求方式:GET/POST
    請求主機:
    
  請求頭:
  空行:
  請求體:  
#4、請求頭
  
User-agent:告訴它這是瀏覽器發過來的請求(請求頭中如果沒有user-agent客戶端配置,服務端可能將你當做一個非法用戶)務必加上
   host: 請求主機(服務器)
  cookies:cookie用來保存登錄信息
   Referer:由哪一個網址跳轉過來的,如果直接訪問是這個值是空的(用來做防盜鏈和廣告的作用的判斷) 一般做爬蟲都會加上請求頭
   content-type:content-type:"urlencoded"/jason--->告訴服務器我提交數據的類型(psot請求才有的)

#5、請求體
  如果是get方式,請求體沒有內容
  如果是post方式,請求體是format data
  ps:

  1、登錄窗口,文件上傳等,信息都會被附加到請求體內
  
2、登錄,輸入錯誤的用戶名密碼,然后提交,就可以看到post,正確登錄后頁面通常會跳轉,無法捕捉到post

   關於contentype詳解

          瀏覽器------------------>服務器          
          1 針對post請求(post請求才有請求體)
          2 向服務器發送post請求有哪些形式:
                form表單 (urlencoded編碼格式)
                    user=yuan
                    pwd=123                    
                Ajax(urlencoded編碼格式)
                     a=1
                     b=2
         
              請求協議格式字符串
              發送urlencoded編碼格式數據
              '''
                  請求首行
                  請求頭
                  content-type:"urlencoded"
                  空行
                  請求體 #  user=yuan&pwd=123   urlencoded編碼格式
              '''
              發送json數據
               '''
                  請求首行
                  請求頭
                  content-type:"json"
                  空行
                  請求體 #  {"user":"yuan","pwd":123}   json編碼格式
              '''

 

  2.request爬取數據的流程

requests使用流程:
    -pip install requests
    - 指定url
    - 發起請求
    - 獲取響應回來的頁面數據
    - 持久化存儲

 

import requests

#爬取搜狗首頁的頁面數據
#1.指定url
url = 'https://www.sogo.com/'
#2.發起請求:get方法會返回一個響應對象
response = requests.get(url=url)
#3.獲取頁面數據
page_text = response.text
#4.持久化存儲
with open('sogou.html','w',encoding='utf-8') as fp:
  fp.write(page_text)

  3.帶User-Agent的請求

  • User-Agent:請求載體的身份標識
  • 反爬機制:瀏覽器會請求頭的UA來檢測是用戶請求還是機器請求
  • 反反爬策略:獲取UA作為request的參數傳進去,模擬一個正常的用戶(瀏覽器) 

例子:

 

url = 'https://www.qiushibaike.com/text/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
}
#手動設定請求的請求頭信息
response = requests.get(url=url,headers=headers)
print(response.text)

  拿UA:

 

  4.帶參數的request

某些網站會帶着我們輸入的參數進行請求:
看一個實例:
  
import requests
kw=input('請輸入一個詞語')
params={
'wd':kw
}
url='https://www.baidu.com/s'
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
response=requests.get(url=url,params=params,headers=headers)

page_content=response.content #響應體的content是二進制的內容,text是文本內容

filename=kw+'.html'
with open(filename,'wb') as f:
f.write(response.content)

  

  5.帶coockies的請求

import uuid
import requests

url = 'http://httpbin.org/cookies'  #這個網址可以做測試使用
cookies = dict(sbid=str(uuid.uuid4()))

res = requests.get(url, cookies=cookies)
print(res.text)

  6.帶session對象的請求(比cookies好用)

#實例化一個是session對象,session對象包含着cookies
session=request.session()
#session對象可以直接發起請求的 session.get() session.post()

 

  7.request的post請求  

1. post請求和get請求大致相同:post(url,headers,data/jason)就是參數的名字不一樣而已,get請求參數是在params字典里面,
post請求參數在data或者jsaon里面(psot請求也可以有params參數,用來做跳轉?next=)
  形式: requests.post(url="/login/",headers={},cookies={},params={"next":"index"},data={},json={})
2.來看一個例子,爬取百度翻譯的結果    import requests import json url='https://fanyi.baidu.com/sug' headers={ 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36' } kw=input('請輸入一個詞') data={ 'kw':kw } response=requests.post(url=url,headers=headers,data=data) print(response.json())


3,看一下jason和contentype的區別
import requests
res1=requests.post(url='http://httpbin.org/post', data={'name':'yuan'}) #沒有指定請求頭,#默認的請求頭:application/x-www-form-urlencoed
print(res1.json())

res2=requests.post(url='http://httpbin.org/post',json={'age':"22",}) #默認的請求頭:application/json
print(res2.json())

{'args': {}, 'data': '', 'files': {}, 'form': {'name': 'yuan'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '9', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.21.0'}, 'json': None, 'origin': '121.35.181.66, 121.35.181.66', 'url': 'https://httpbin.org/post'}


{'args': {}, 'data': '{"age": "22"}', 'files': {}, 'form': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '13', 'Content-Type': 'application/json', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.21.0'}, 'json': {'age': '22'}, 'origin': '121.35.181.66, 121.35.181.66', 'url': 'https://httpbin.org/post'}

  

   8.request值ajax請求

import requests

#url和參數,直接用抓包工具去請求頭和Query String ParamMetres抓取
url='https://movie.douban.com/j/chart/top_list'
#因為是ajax發起的get請求,所以數據用params
params={
    'type':'24',
    'interval_id':'100:90',
    'action':'',
    'start': '20',
    'limit':'20'
}
headers={
    'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'
}
#從response看到Content-Type: application/json; charset=utf-8,說明是支持中文顯示的
jason_text=requests.get(url=url,headers=headers,params=params).text
print(jason_text)

   9.request的ajax的post請求

import requests

kw=input('請輸入一個城市')
#這邊要記住,這是post請求,post請求不能不會把參數直接拼接在路徑后面,所有網址拷過來就不要動了
url='http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'
}
# post請求用的是data,記得啊
data={
    'cname':'',
    'pid': '',
    'keyword': kw,
    'pageIndex': '1',
    'pageSize': '10'
}
#抓包工具能看到他是text類型,utf-8吧編碼的,支持中文顯示
page_text=requests.post(url=url,headers=headers,data=data).text
print(page_text)

   10.基於ajax的動態加載網址

import requests

url='http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList'
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'
}
#做循環作用的拿到所有頁碼的
for i in range(100):

    data={
        'on': 'true',
        'page': '1',
        'pageSize': '15',
        'productName':'',
        'conditionType': i,
        'applyname': '',
        'applysn': ''
    }
    # #json()方法:返回是一個序列化號的json對象
    jason_text=requests.post(url=url,data=data,headers=headers).json()
    jason_list=jason_text['list']
    #拿到所有企業的id(ajax發出的post請求是根據企業id返回結果的)
    id_list=[]
    for dic in jason_list:
        id_list.append(dic['ID'])
    #發出第二次請求,帶上企業id就能拿到具體的值了
    url1='http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
    for id in id_list:
        data1={
            'id': id
        }
        json_text=requests.post(url=url1,data=data1,headers=headers).text
        print(json_text)

   11.帶有代理的請求

import requests

res=requests.get('http://httpbin.org/ip', proxies={'http':'111.177.177.87:9999'}).json()

 

 

三.reponse的屬性

  1.常見屬性

import requests
response=requests.get('https://www.jd.com/')
print(response.status_code)
print(response.text)  #文本內容
print(response.content) #二進制內容
print(response.headers)  #響應頭
print((response.cookies)) #響應的cookie
print(response.cookies.get_dict()) 
print(response.cookies.items())
print(response.url)  #響應的url
print(response.history) #如果有重定向重定向之前相應的數據
print(response.encoding) #響應體的編碼

  2.編碼問題

import requests
response=requests.get('http://www.autohome.com/news')
response.encoding='gbk' #汽車之家網站返回的頁面內容為gb2312編碼的,而requests的默認編碼為ISO-8859-1,如果不設置成gbk則中文亂碼
with open("res.html","w") as f:  #解碼過程是在拿text過程中執行的
    f.write(response.text)

   3.下載二進制內容

import requests
response=requests.get('http://bangimg1.dahe.cn/forum/201612/10/200447p36yk96im76vatyk.jpg')
with open("res.png","wb") as f:
    # f.write(response.content) # 比如下載視頻時,如果視頻100G,用response.content然后一下子寫到文件中是不合理的
    for line in response.iter_content():  #用迭代器可以一段一段,不知於把自己的硬盤搞垮了
        f.write(line)

 

   4,解析jason數據

import requests
import json
 
response=requests.get('http://httpbin.org/get')
res1=json.loads(response.text) #太麻煩
res2=response.json() #直接獲取json數據,和上面的同理
print(res1==res2)

  

  5. Redirection and History

  默認情況下,除了 HEAD, Requests 會自動處理所有重定向。可以使用響應對象的 history 方法來追蹤重定向。Response.history 是一個 Response 對象的列表,

為了完成請求而創建了這些對象。這個對象列表按照從最老到最近的請求進行排序。

>>> r = requests.get('http://github.com')
>>> r.url
'https://github.com/'
>>> r.status_code
200
>>> r.history
[<Response [301]>]

  另外,還可以通過 allow_redirects 參數禁用重定向處理:

>>> r = requests.get('http://github.com', allow_redirects=False)
>>> r.status_code
301
>>> r.history
[]  

   6.相應狀態碼

    response.status_code

    #正常情況下我們是通過判斷相應的狀態碼是不是200 來判斷是否請求成功

    我們也可可以通過相應對象的方法來直接捕獲狀態碼不是200的響應

  1.相應狀態碼不是200的  

import requests

bad_r = requests.get('http://httpbin.org/status/404')
bad_r.status_code   #404
bad_r.raise_for_status()  #當響應的狀態碼不是200的時候調用這個接口,會拋出異常,哦我們呢捕獲這個異常就好了


Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "D:\python37\lib\site-packages\requests\models.py", line 941, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: NOT FOUND for url: http://httpbin.org/status/404

  2.狀態碼是200

import requests
res=requests.get('https://www.baidu.com/')
res.status_code  #200
res.raise_for_status()  #當響應的狀態碼是200的時候,調用這個接口的返回值的None
print(res.raise_for_status())
None

   3.判斷響應狀態碼中和請求的狀態碼中的ok(200)是不是相等的

   

importrequest
res=requests.get('https://www.baidu.com/')
res.status_code  #200
res.status_code==requests.codes.ok
True

         所以通用的請求狀態碼判斷這塊可以這么寫:

import requests

try:
    res=requests.get('https://www.baidu.com/')
    res.raise_for_status()

except requests.HTTPError as error:
    print('status_error')
except:
    print('other error')

 

 

  

 

  有一篇博文寫的很簡潔,可參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM