爬蟲—模擬登陸
阿新 • • 發佈:2020-08-09
報錯HttpConnectinPool:
原因:
- 1.短時間內發起了高頻的請求導致ip被禁。
- 2.傳送高頻的請求且請求成功後沒有被及時斷開,導致http連線池(http連線物件)中的連線資源被耗盡。
解決: - 1.代理
- 2.headers中加入
Conection:"close"
,表示請求後連線立即斷開。
代理
代理:代理伺服器,可以接受請求然後將其轉發。
匿名度
- 透明:知道你使用了代理並且知道你的真實ip
- 匿名:知道你使用了代理,但是不知道你的真實ip
- 高匿:啥也不知道
型別: - http,只能轉發http請求
- https,只能轉發https請求
免費代理: - www.goubanjia.com
- 快代理
- 西祠代理
- http://http.zhiliandaili.cn/
使用代理
importrequests
headers={
'User-Agent':'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/76.0.3809.132Safari/537.36',
'Connection':"close"
}
url='https://www.baidu.com/s?ie=UTF-8&wd=ip'
page_text=requests.get(url,headers=headers,proxies={'https':'1.197.204.153:9999' }).text
withopen('ip.html','w',encoding='utf-8')asfp:
fp.write(page_text)
代理可能隨時被封
解決方法:代理池
#代理池:列表
importrandom
proxy_list=[
{'https':'121.231.94.44:8888'},
{'https':'131.231.94.44:8888'},
{'https':'141.231.94.44:8888'}
]
url='https://www.baidu.com/s?wd=ip'
page_text=requests.get(url,headers=headers,proxies=random.choice(proxy_list)).text
with open('ip.html','w',encoding='utf-8')asfp:
fp.write(page_text)
使用購買代理並爬取代理
推薦網址:http://http.zhiliandaili.cn/
(代理精靈)
- 進入網址後註冊登陸
- 購買後進入API提取
- 選擇提取型別,提取數量,資料格式(HTML),分隔符(換行),是否去重等等
- 選擇好後點擊生成API連結,複製連結
#檢測IP是否可用
deffunc_ip(proxy_list_http)
#隨便訪問一個網址
response=requests.get('https://www/sogou.com',headers=headers,proxies={'https':ip})
#status_code響應狀態碼
ifresponse.status_code=='200':
returnTrue
else;returnFalse
#從代理精靈中提取代理ip
API_url='http://t.11jsq.com/index.php/api/entry?method=proxyServer.generate_api_url&packid=1&fa=0&fetch_key=&groupid=0&qty=4&time=1&pro=&city=&port=1&format=html&ss=5&css=&dt=1&specialTxt=3&specialJson=&usertype=2'
page_text=requests.get(ip_url,headers=headers).text
tree=etree.HTML(page_text)
ip_list=tree.xpath('//body//text()')
ip_list#購買的IP
使用購買的IP爬取免費IP構建代理池
fromlxmlimportetree
#爬取西祠代理
proxy_list_http=[]
proxy_list_https=[]
defget_ip(url,headers,proxies):
page_text=requests.get(url,headers=headers,proxies={'https':ip_port}).text
tree=etree.HTML(page_text)
#tr_list=tree.xpath('//*[@id="ip_list"]/tbody/tr')
#tbody不可以出現在xpath表示式中,否則表示式會失效
tr_list=tree.xpath('//*[@id="ip_list"]//tr')[1:]
fortrintr_list:
ip=tr.xpath('./td[2]/text()')[0]
port=tr.xpath('./td[3]/text()')[0]
t_type=tr.xpath('./td[6]/text()')[0]
ips=ip+':'+port
#若IP過多,可以存進資料庫中,但效率不高,可以直接購買ip
ift_type=='HTTP':
dic={
t_type:ips
}
proxy_list_http.append(dic)
else:
dic={
t_type:ips
}
proxy_list_https.append(dic)
url='https://www.xicidaili.com/nn/%d'
forpageinrange(1,20):
new_url=format(url%page)
ip_port=random.choice(ip_list)
iffunc_ip(ip_port):
get_ip(new_url,headers,ip_port)
else:
ip_list.remove(ip_port)
print(len(proxy_list_http),len(proxy_list_https))
Cookie的處理
Cookie中有請求相關的狀態資訊,伺服器端可以通過Cookie判斷請求者的身份資訊與狀態資訊。
Cookie的處理:
- 手動處理:將Cookie封裝到headers中
- 自動處理:session物件。可以建立一個session物件,該物件可以像requests一樣進行請求傳送。不同之處在於如果在使用session進行請求傳送的過程中產生了cookie,則cookie會被自動儲存在session物件中。
專案 手動處理Cookie
對雪球網中的新聞資料進行爬取 urlhttps://xueqiu.com/
分析:
- 頁面資料是動態載入的(拖動滾輪,頁面不斷載入,url位址列不重新整理)
- Request Headers欄中有Cookie資訊
- 可以複製Cookie資訊,傳入請求頭中進行爬取
headers={
'User-Agent':'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/76.0.3809.132Safari/537.36',
'Cookie':'aliyungf_tc=AQAAAAl2aA+kKgkAtxdwe3JmsY226Y+n;acw_tc=2760822915681668126047128e605abf3a5518432dc7f074b2c9cb26d0aa94;xq_a_token=75661393f1556aa7f900df4dc91059df49b83145;xq_r_token=29fe5e93ec0b24974bdd382ffb61d026d8350d7d;u=121568166816578;device_id=24700f9f1986800ab4fcc880530dd0ed'
}
url='https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id=20349203&count=15&category=-1'
page_text=requests.get(url=url,headers=headers).json()
page_text
直接將Cookie新增至請求頭,但Cookie有時間限制,每次爬蟲可能需要手動處理,使程式碼不易維護。
使用session物件自動處理Cookie
#建立session物件
session=requests.Session()
#訪問網站首頁,獲取Cookie
session.get('https://xueqiu.com',headers=headers)
#利用session物件爬取頁面
url='https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id=20349203&count=15&category=-1'
page_text=session.get(url=url,headers=headers).json()
page_text
模擬登陸
驗證碼的識別:要基於打碼平臺識別識別驗證碼。
相關平臺:
打碼兔
雲打碼
超級鷹:http://www.chaojiying.com/about.html
本教程使用超級鷹平臺:
- 註冊:(使用者中心身份)
- 登陸:
- 軟體ID-->生成一個軟體ID-->記錄軟體ID
- 開發文件-->選擇python-->下載示例程式碼
- 價格體系-->選擇驗證碼型別並記錄
#貼上示例程式碼
importrequests
fromhashlibimportmd5
classChaojiying_Client(object):
def__init__(self,username,password,soft_id):
self.username=username
password=password.encode('utf8')
self.password=md5(password).hexdigest()
self.soft_id=soft_id
self.base_params={
'user':self.username,
'pass2':self.password,
'softid':self.soft_id,
}
self.headers={
'Connection':'Keep-Alive',
'User-Agent':'Mozilla/4.0(compatible;MSIE8.0;WindowsNT5.1;Trident/4.0)',
}
defPostPic(self,im,codetype):
"""
im:圖片位元組
codetype:題目型別參考http://www.chaojiying.com/price.html
"""
params={
'codetype':codetype,
}
params.update(self.base_params)
files={'userfile':('ccc.jpg',im)}
r=requests.post('http://upload.chaojiying.net/Upload/Processing.php',data=params,files=files,headers=self.headers)
returnr.json()
defReportError(self,im_id):
"""
im_id:報錯題目的圖片ID
"""
params={
'id':im_id,
}
params.update(self.base_params)
r=requests.post('http://upload.chaojiying.net/Upload/ReportError.php',data=params,headers=self.headers)
returnr.json()
模擬登陸古詩文網
urlhttps://so.gushiwen.cn/user/login.aspx?from=http://so.gushiwen.cn/user/collect.aspx
#識別古詩文網登陸頁面中的驗證碼
deftranformImgData(imgPath,t_type):
#超級鷹使用者名稱,超級鷹使用者名稱的密碼,軟體ID
chaojiying=Chaojiying_Client('chongxiao','chongxiao','907070')
#本地圖片檔案路徑
im=open(imgPath,'rb').read()
#chaojiying返回一個字典,pic_str鍵的值是圖形中的驗證碼
returnchaojiying.PostPic(im,t_type)['pic_str']
url='https://so.gushiwen.cn/user/login.aspx?from=http://so.gushiwen.cn/user/collect.aspx'
page_text=requests.get(url,headers=headers).text
tree=etree.HTML(page_text)
img_src='https://so.gushiwen.org'+tree.xpath('//*[@id="imgCode"]/@src')[0]
img_data=requests.get(img_src,headers=headers).content
withopen('./code.jpg','wb')asfp:
fp.write(img_data)
#1004驗證碼型別
tranformImgData('./code.jpg',1004)
分析:
- 將分析成功的字串驗證碼傳送給古詩文網
- 在瀏覽器直接登入,用抓包工具,找到哪一個資料包傳送的登入請求,一般為POST請求,且Form Data中有請求的使用者名稱與密碼資料。
- 找到傳送登入請求的資料包為login.aspx?from…;從General中找到Request URL,並且發現該資料包請求頭中有Cookie。
- 退出賬號再次登入,發現From Data的前兩個引數與第一次不一樣,即為動態變化的。
- 猜測動態引數是由隱藏的input標籤攜帶,在登入頁面,找到對應的頁面資料包,進行全域性全域性搜尋,搜尋變化引數的鍵值,結果與猜測一樣。
- 選擇隱藏的input標籤,右鍵copy Xpath表示式。
#模擬登陸
s=requests.Session()
url='https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx'
page_text=s.get(url,headers=headers).text
tree=etree.HTML(page_text)
img_src='https://so.gushiwen.org'+tree.xpath('//*[@id="imgCode"]/@src')[0]
#此處用requests物件請求,卻發現仍無法請求成功,經分析發現,登入的Cookie是由獲取圖片的請求攜帶的。
img_data=s.get(img_src,headers=headers).content
withopen('./code.jpg','wb')asfp:
fp.write(img_data)
#動態獲取變化的請求引數
__VIEWSTATE=tree.xpath('//*[@id="__VIEWSTATE"]/@value')[0]
__VIEWSTATEGENERATOR=tree.xpath('//*[@id="__VIEWSTATEGENERATOR"]/@value')[0]
code_text=tranformImgData('./code.jpg',1004)
print(code_text)
login_url='https://so.gushiwen.org/user/login.aspx?from=http%3a%2f%2fso.gushiwen.org%2fuser%2fcollect.aspx'
data={
'__VIEWSTATE':__VIEWSTATE,
'__VIEWSTATEGENERATOR':__VIEWSTATEGENERATOR,
'from':'http://so.gushiwen.org/user/collect.aspx',
'email':'[email protected]',
'pwd':'bobo328410948',
'code':code_text,
'denglu':'登入',
}
page_text=s.post(url=login_url,headers=headers,data=data).text
withopen('login.html','w',encoding='utf-8')asfp:
fp.write(page_text)
動態變化的請求引數:通常情況下動態變化的請求引數都會被隱藏在前臺頁面原始碼中。
攜帶Cookie的響應:伺服器傳送Cookie不一定是請求登入頁面傳送的,也可能是請求某個動態資料或圖片傳送的,若用session物件處理Cookie,則最好每一個請求都用session物件傳送。