爬蟲簡介和requests模塊
- 2020 年 4 月 8 日
- 筆記
爬蟲介紹
爬蟲的本質就是模擬發送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有優勢.