爬蟲簡介和requests模塊

爬蟲介紹

爬蟲的本質就是模擬發送http請求(requests模塊),之後解析返回的數據(re,bs4,lxml,json等模塊),最後將數據入庫(redis,mysql,mongodb)。

app的爬蟲,本質上是一模一樣的。

python做爬蟲的優勢在於:包多,而且有爬蟲的框架scrapy,是一個性能很高的爬蟲框架,類似後台框架中的Django,該框架,大而全(爬蟲相關的東西都集成了。)

百度和谷歌其實就是個大爬蟲,在百度搜索,其實是去百度的服務器的庫搜的,百度一直開着爬蟲,一刻不停的在互聯網上爬取,把頁面存儲到自己庫中

requests模塊

該模塊可以模擬http請求,是基於urlib2封裝出來的模塊(urlib2:內置庫,不太好用,繁瑣)。

安裝:

pip3 install requests  

requests模塊

1、requests模塊的基本使用

import requests    # get,delete,post等等請求方式都是調用的requests模塊中的request函數  ret = requests.post()  # ret = requests.request('post', )  內部都是調用request函數  ret = requests.delete()  ret = requests.get('https://www.cnblogs.com')  print(ret.status_code)  # 響應狀態碼  print(ret.text)  # 響應體,轉成字符串  print(ret.content)  # 響應體,二進制的,用於獲取視頻等  

2、get 請求攜帶參數,調用params參數,其本質上還是調用urlencode

# 方式一    ret = requests.get('https://www.baidu.com/s?wd=python&pn=1',                      headers={                          'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',                      })  print(ret.text)    # 方式二(建議使用方式二),因為中文會自動轉碼  ret = requests.get('https://www.baidu.com/',                     params={                         'wd': "美女",                         'pn': 1                     },                     headers={                          'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',                      })  print(ret.text)  

3、攜帶headers,請求頭是將自身偽裝成瀏覽器的關鍵

ret = requests.get('http://0.0.0.0:8001/?name=%E7%BE%8E%E5%A5%B3',                     headers={                         # 標誌,什麼東西發出的請求,瀏覽器信息,django框架,從哪取?(meta)                         'User-Agent': '',                         # 上一個頁面的地址,圖片防盜鏈,大型網站通常回根據該參數判斷請求的來源                         'Referer': 'xxx',                         # 存放cookie的地方                         'Cookie': ''                     })  print(ret)    """  圖片防盜鏈:如果圖片的referer不是我自己的網站,就直接禁止掉  <img src="https://www.lgstatic.com/lg-community-fed/community/modules/common/img/avatar_default_7225407.png">  """  

4、帶cookie

隨機字符串(用戶信息:也代表session),不管後台用的token認證,還是session認證,一旦登陸了,帶着cookie發送請求,表示登陸了(可以下單,可以12306買票,可以評論)

# 第一種方式    ret = requests.get('http://0.0.0.0:8001/?name=%E7%BE%8E%E5%A5%B3',                     headers={                         'cookie': 'key3=value;key2=value',                     })    # 第二種方式    ret = requests.get('http://0.0.0.0:8001/?name=%E7%BE%8E%E5%A5%B3',                     cookies={"islogin":"xxx"})  print(ret)  

5、發送post請求(註冊,登陸),攜帶數據(body)

# data=None, json=None    # data: urlencoded編碼  ret = requests.post('http://0.0.0.0:8001/',data={'name':"lqz",'age':18})    # json: json編碼  import json  data = json.dumps({'name':"lqz",'age':18})  ret = requests.post('http://0.0.0.0:8001/',json=data)  print(ret)  # 注意:編碼格式是請求頭中帶的,所有我可以手動修改,在headers中改  

6、session對象

session = requests.session()  # 跟requests.get/post用起來完全一樣,但是它處理了cookie  # 假設是一個登陸,並且成功登陸,就可以使用session.post()進行請求,但無需攜帶cookie  session.post()  # 再向該網站發請求,就是登陸狀態,不需要手動攜帶cookie  session.get("地址")  

7、響應對象

print(respone.text)   # 響應體轉成str  print(respone.content) # 響應體二進制(圖片,視頻)    print(respone.status_code) # 響應狀態碼  print(respone.headers) # 響應頭  print(respone.cookies) # 服務端返回的cookie  print(respone.cookies.get_dict()) # 轉成字典  print(respone.cookies.items())    print(respone.url)  # 當次請求的地址  """  print(respone.history) # 如果有重定向,放到一個列表中  ret=requests.post('http://0.0.0.0:8001/')  ret=requests.get('http://0.0.0.0:8001/admin')  #不要誤解  ret=requests.get('http://0.0.0.0:8001/user')  print(ret.history)  # 只能獲取到ret=requests.get('http://0.0.0.0:8001/user')的重定向網址  # 上面的三個ret是不同的三個響應,ret.history只能獲取到一個響應對象的重定向的歷史網址  """    print(respone.encoding) # 編碼方式    # response.iter_content() # 視頻,圖片迭代取值,避免一次取完,撐爆內存  with open("a.mp4",'wb') as f:      for line in response.iter_content():          f.write(line)  

8、亂碼問題

ret.encoding='gbk'  ret = requests.get('http://0.0.0.0:8001/user')    # ret.apparent_encoding 獲取當前頁面採用的編碼  ret.encoding = ret.apparent_encoding  

9、解析json

# 返回數據,有可能是json格式,有可能是html格式  ret = requests.get('http://0.0.0.0:8001/')  print(type(ret.text))  print(ret.text)    a = ret.json()  print(a['name'])  print(type(a))  

10、使用代理

# 正向代理  # django如何拿到客戶端ip地址 META.get("REMOTE_ADDR")    # 使用代理有什麼用? 可以讓服務端以為來訪問的是代理的網站  # 一些網站,會限制ip的訪問次數,因此我們可以使用代理池,去訪問該網站,突破限制  ret = requests.get('http://0.0.0.0:8001/', proxies={'http':'地址'})  print(type(ret.text))  print(ret.text)  

11、異常處理

# 用try except捕獲一下 就用它就行了:Exception  

12、上傳文件(爬蟲用的比較少,一般用於後台寫服務,將爬取下來的文件上傳給其他服務端)

file={'myfile':open("1.txt",'rb')}  ret=requests.post('http://0.0.0.0:8001/',files=file)  print(ret.content)  

利用requests模塊爬取梨視頻

############  # 2 爬取視頻  #############  #categoryId=9 分類id  #start=0 從哪個位置開始,每次加載12個  # https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=9&start=0    import requests  import re  ret=requests.get('https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=9&start=0')  # print(ret.text)  # 正則取解析  reg='<a href="(.*?)" class="vervideo-lilink actplay">'  video_urls=re.findall(reg,ret.text)  print(video_urls)  for url in video_urls:      ret_detail=requests.get('https://www.pearvideo.com/'+url)      reg='srcUrl="(.*?)",vdoUrl=srcUrl'      mp4_url=re.findall(reg,ret_detail.text)[0] #type:str      # 下載視頻      video_content=requests.get(mp4_url)      video_name=mp4_url.rsplit('/',1)[-1]      with open(video_name,'wb') as f:          for line in video_content.iter_content():              f.write(line)  

代碼可以優化,使用多線程進行爬取

模擬登陸某網站

############  # 3 模擬登陸某網站  #############    import requests    ret = requests.post('http://www.aa7a.cn/user.php',                      data={                          'username': '[email protected]',                          'password': 'lqz123',                          'captcha': 'f5jn',                          'remember': '1',                          'ref': 'http://www.aa7a.cn/',                          'act': 'act_login',                      })  cookie=ret.cookies.get_dict()  print(cookie)  # 如果不出意外,咱么就登陸上了,再向首頁發請求,首頁返回的數據中就有[email protected]  ret1=requests.get('http://www.aa7a.cn/',cookies=cookie)  # ret1=requests.get('http://www.aa7a.cn/')    print('[email protected]' in ret1.text)      # 秒殺小米手機,一堆小號  # 定時任務:一到時間,就可以發送post請求,秒殺手機      # 以後碰到特別難登陸的網站,代碼登陸不進去怎麼辦?    # 之所以要登陸,就是為了拿到cookie,下次發請求(如果程序拿不到cookie,自動登陸不進去)  # 就手動登陸進去,然後用程序發請求  

代理

## 代理  # 網上會有免費代理,不穩定    # 使用代理有什麼用?  # drf:1分鐘只能訪問6次,限制ip  # 每次發請求都使用不同代理,random一下  # 代理池:列表,其實就是代理池的一種  import requests  ret=requests.get('https://www.cnblogs.com/',proxies={'http':'222.85.28.130:40505'})    #高匿:服務端,根本不知道我是誰  #普通:服務端是能夠知道我的ip的  # http請求頭中:X-Forwarded-For:代理的過程,可以獲取到最初發起請求的客戶端ip地址和代理服務的ip地址,但對於高匿,是無法獲取到的最初請求的客戶端ip地址。  ret=requests.get('http://101.133.225.166:8080',proxies={'http':'222.85.28.130:40505'})  ret=requests.get('http://101.133.225.166:8080',proxies={'http':'114.99.54.65:8118'})  print(ret.text)    X-Forwarded-For: <client>, <proxy1>, <proxy2>    <client>  客戶端的IP地址。  <proxy1>, <proxy2>  如果一個請求經過了多個代理服務器,那麼每一個代理服務器的IP地址都會被依次記錄在內。也就是說,最右端的IP地址表示最近通過的代理服務器,而最左端的IP地址表示最初發起請求的客戶端的IP地址。  

正向代理和反向代理

正向代理即是客戶端代理,代理客戶端,服務端不知道實際發起請求的客戶端。

反向代理即是服務端代理,代理服務端,客戶端不知道實際提供服務的服務端。

正向代理中,proxy和client同屬一個LAN,對server透明;
反向代理中,proxy和server同屬一個LAN,對client透明。
實際上proxy在兩種代理中做的事都是代為收發請求和響應,不過從結構上來看正好左右互換了下,所以把後出現的那種代理方式叫成了反向代理

靜態,動態和偽靜態

靜態是指http://127.0.0.1/user.html這種url,頁面中的內容是固定死的,數據也是死的,加載速度快,容易被搜索引擎爬取收錄,可以優化seo。

動態是指http://127.0.0.1/?name='張三'&age=12這種url,頁面的數據是從數據庫中獲取的,加載速度較慢,不容易被搜索引擎爬取收錄,seo沒有優勢。

偽靜態是指http://127.0.0.1/user.html通過一些路徑規則(正則表達式)將動態url偽裝為靜態url,加載速度較慢,seo有優勢。

總結:

靜態url: 不方便管理,修改麻煩, seo優化相當好.

動態url : 方便管理,修改簡單, seo沒優勢.

偽靜態: 結合兩者的優勢. 方便管理, seo有優勢.