請求庫之urllib,requests及工具selenium


urllib模塊

urllib是Python自帶的一個用於爬蟲的庫,其主要作用就是可以通過代碼模擬瀏覽器發送請求。其常被用到的子模塊在Python3中的為urllib.request和urllib.parse,在Python2中是urllib和urllib2。

一、使用流程:

  • 指定url
  • 基於urllib的request子模塊發起請求
  • 獲取響應中的數據值
  • 持久化存儲

二、urlopen函數原型:

urllib.request.urlopen(url, data=None, timeout=<object object at 0x10af327d0>, *, cafile=None, capath=None, cadefault=False, context=None)在日常開發中,我們能用的只有url和data這兩個參數。

  • url參數:指定向哪個url發起請求
  • url的特性:url必須為ASCII編碼的數據值。所以我們在爬蟲代碼中編寫url時,如果url中存在非ASCII編碼的數據值,則必須對其進行ASCII編碼后,該url方可被使用。
    1. get: word = urllib.parse.quote("人民幣")
    2. post: data = { 'kw':'西瓜'} data = urllib.parse.urlencode(data) data = data.encode() urlencode(返回值類型為str)
  • data參數:可以將post請求中攜帶的參數封裝成字典的形式傳遞給該參數
  • urlopen函數返回的響應對象,相關函數調用介紹:
    1. response.headers():獲取響應頭信息
    2. response.getcode():獲取響應狀態碼
    3. response.geturl():獲取請求的url
    4. response.read():獲取響應中的數據值(字節類型)

三、其他

  • 反爬機制:網站檢查請求的UA,如果發現UA是爬蟲程序,則拒絕提供網站數據。
  • User-Agent(UA):請求載體的身份標識.
  • 反反爬機制:偽裝爬蟲程序請求的UA
  • 通過自定義請求對象,用於偽裝爬蟲程序請求的身份。
"""
基礎使用
"""
# 需求:爬取搜狗首頁的頁面數據
import urllib.request
#1.指定url
url = 'https://www.sogou.com/'

#2.發起請求:urlopen可以根據指定的url發起請求,切返回一個響應對象
response = urllib.request.urlopen(url=url)

#3.獲取頁面數據:read函數返回的就是響應對象中存儲的頁面數據(byte)
page_text = response.read()

#4.持久化存儲
with open('./sougou.html','wb') as fp:
    fp.write(page_text)
    print('寫入數據成功')


"""
get:
"""
# 需求:爬取指定詞條所對應的頁面數據
import urllib.request
import urllib.parse
#指定url
url = 'https://www.sogou.com/web?query='
#url特性:url不可以存在非ASCII編碼的字符數據
word = urllib.parse.quote("人民幣")
url += word #有效的url
#發請求
response = urllib.request.urlopen(url=url)

#獲取頁面數據
page_text = response.read()

with open('renminbi.html','wb') as fp:
    fp.write(page_text)


"""
UA偽裝
"""
import urllib.request
url = 'https://www.baidu.com/'
# UA偽裝
# 1.子制定一個請求對象
headers = {
    # 存儲任意的請求頭信息
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36'
}
# 該請求對象的UA進行了成功的偽裝
request = urllib.request.Request(url=url, headers=headers)
# 2.針對自制定的請求對象發起請求
response = urllib.request.urlopen(request)
print(response.read())


"""
post
"""
import urllib.request
import urllib.parse
#1.指定url
url = 'https://fanyi.baidu.com/sug'
#post請求攜帶的參數進行處理  流程:
#1.將post請求參數封裝到字典
data = {
    'kw':'西瓜'
}
#2.使用parse模塊中的urlencode(返回值類型為str)進行編碼處理
data = urllib.parse.urlencode(data)
#3.將步驟2的編碼結果轉換成byte類型
data = data.encode()

#2.發起post請求:urlopen函數的data參數表示的就是經過處理之后的post請求攜帶的參數
response = urllib.request.urlopen(url=url,data=data)

response.read()
urllib使用

requests模塊

  • 介紹:使用requests可以模擬瀏覽器的請求,比起之前用到的urllib,requests模塊的api更加便捷(本質就是封裝了urllib3)
  • 注意:requests庫發送請求將網頁內容下載下來以后,並不會執行js代碼,這需要我們自己分析目標站點然后發起新的request請求
  • 安裝:pip3 install requests
  • 各種請求方式:常用的就是requests.get()和requests.post()
import requests
r = requests.get('https://api.github.com/events')
r = requests.post('http://httpbin.org/post', data = {'key':'value'})
r = requests.put('http://httpbin.org/put', data = {'key':'value'})
r = requests.delete('http://httpbin.org/delete')
r = requests.head('http://httpbin.org/get')
r = requests.options('http://httpbin.org/get')
各種請求方式
"""
get請求
"""
import requests
#指定url
url = 'https://www.sogou.com/'
#發起get請求:get方法會返回請求成功的相應對象
response = requests.get(url=url)
#獲取響應中的數據值:text可以獲取響應對象中字符串形式的頁面數據
page_data = response.text
print(page_data)
#content獲取的是response對象中二進制(byte)類型的頁面數據
print(response.content)
#返回一個響應狀態碼
print(response.status_code)
#返回響應頭信息
print(response.headers)
#獲取請求的url
print(response.url)
#持久化操作
with open('./sougou.html','w',encoding='utf-8') as fp:
    fp.write(page_data)


"""
get請求帶參方式1:
"""
import requests
url = 'https://www.sogou.com/web?query=周傑倫&ie=utf-8'
response = requests.get(url=url)
page_text = response.text
with open('./zhou.html','w',encoding='utf-8') as fp:
    fp.write(page_text)

"""
get請求帶參方式2:
自定義請求頭信息
"""
# 自定義請求頭信息
import requests
url = 'https://www.sogou.com/web'
#將參數封裝到字典中
params = {
    'query':'周傑倫',
    'ie':'utf-8'
}
#自定義請求頭信息
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
response = requests.get(url=url,params=params,headers=headers)
response.status_code


"""
post請求
需求:登錄豆瓣網,獲取登錄成功后的頁面數據
"""
import requests
#1.指定post請求的url
url = 'https://accounts.douban.com/login'
#封裝post請求的參數
data = {
    "source": "movie",
    "redir": "https://movie.douban.com/",
    "form_email": "15027900535",
    "form_password": "bobo@15027900535",
    "login": "登錄",
}
#自定義請求頭信息
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
#2.發起post請求
response = requests.post(url=url,data=data,headers=headers)
#3.獲取響應對象中的頁面數據
page_text = response.text
#4.持久化操作
with open('./douban.html','w',encoding='utf-8') as fp:
    fp.write(page_text)


"""
基於ajax的get請求
-需求:抓取豆瓣電影上電影詳情的數據
"""
import requests
url = 'https://movie.douban.com/j/chart/top_list?'
#封裝ajax的get請求中攜帶的參數
params = {
    'type':'5',
    'interval_id':'100:90',
    'action':'',
    'start':'100',
    'limit':'20'
}
#自定義請求頭信息
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
response = requests.get(url=url,params=params,headers=headers)
#獲取響應內容:響應內容為json串
print(response.text)



"""
基於ajax的post請求
- 需求:爬去肯德基城市餐廳位置數據
"""

import requests
#1指定url
post_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
#處理post請求的參數
data = {
    "cname": "",
    "pid": "",
    "keyword": "上海",
    "pageIndex": "1",
    "pageSize": "10",
}
#自定義請求頭信息
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
#2發起基於ajax的post請求
response = requests.post(url=post_url,headers=headers,data=data)
#獲取響應內容:響應內容為json串
print(response.text)

"""
綜合項目實戰
- 需求:爬取搜狗知乎某一個詞條對應一定范圍頁碼表示的頁面數據
"""
# 前三頁頁面數據(1,2,3)
import requests
import os

# 創建一個文件夾
if not os.path.exists('./pages'):
    os.mkdir('./pages')
word = input('enter a word:')
# 動態指定頁碼的范圍
start_pageNum = int(input('enter a start pageNum:'))
end_pageNum = int(input('enter a end pageNum:'))
# 自定義請求頭信息
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
# 1.指定url:設計成一個具有通用的url
url = 'https://zhihu.sogou.com/zhihu'
for page in range(start_pageNum, end_pageNum + 1):
    param = {
        'query': word,
        'page': page,
        'ie': 'utf-8'
    }
    response = requests.get(url=url, params=param, headers=headers)

    # 獲取響應中的頁面數據(指定頁碼(page))
    page_text = response.text

    # 進行持久化存儲
    fileName = word + str(page) + '.html'
    filePath = 'pages/' + fileName
    with open(filePath, 'w', encoding='utf-8') as fp:
        fp.write(page_text)
        print('第%d頁數據寫入成功' % page)


"""
requests模塊高級:
- cookie:
    基於用戶的用戶數據
    - 需求:爬取張三用戶的豆瓣網的個人主頁頁面數據
- cookie作用:服務器端使用cookie來記錄客戶端的狀態信息。
實現流程:
    1.執行登錄操作(獲取cookie)
    2.在發起個人主頁請求時,需要將cookie攜帶到該請求中
    注意:session對象:發送請求(會將cookie對象進行自動存儲)
"""
import requests

session = requests.session()
#1.發起登錄請求:將cookie獲取,且存儲到session對象中
login_url = 'https://accounts.douban.com/login'
data = {
    "source": "None",
    "redir": "https://www.douban.com/people/185687620/",
    "form_email": "15027900535",
    "form_password": "bobo@15027900535",
    "login": "登錄",
}
headers={
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
    }
#使用session發起post請求
login_response = session.post(url=login_url,data=data,headers=headers)

#2.對個人主頁發起請求(session(cookie)),獲取響應頁面數據
url = 'https://www.douban.com/people/185687620/'
response = session.get(url=url,headers=headers)
page_text = response.text

with open('./douban110.html','w',encoding='utf-8') as fp:
    fp.write(page_text)


"""
代理操作:
- 1.代理:第三方代理本體執行相關的事物。生活:代購,微商,中介
- 2.為什么要使用代理?
    - 反爬操作。
    - 反反爬手段
- 3.分類:
    - 正向代理:代替客戶端獲取數據
    - 反向代理:代理服務器端提供數據
- 4.免費代理ip的網站提供商:
    - www.goubanjia.com
    - 快代理
    - 西祠代理
- 5.代碼:
"""
import requests
url = 'http://www.baidu.com/s?ie=utf-8&wd=ip'
headers={
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
    }
#將代理ip封裝到字典
proxy = {
    'http':'77.73.69.120:3128'
}
#更換網路IP
response = requests.get(url=url,proxies=proxy,headers=headers)
with open('./daili.html','w',encoding='utf-8') as fp:
    fp.write(response.text)
常見操作

一、基於GET請求

  • HTTP默認的請求方法就是GET
    1. 沒有請求體
    2. 數據必須在1K之內!
    3. GET請求數據會暴露在瀏覽器的地址欄中
  • GET請求常用的操作:
    1. 在瀏覽器的地址欄中直接給出URL,那么就一定是GET請求
    2. 點擊頁面上的超鏈接也一定是GET請求
    3. 提交表單時,表單默認使用GET請求,但可以設置為POST
#1、基本請求
import requests
response=requests.get('http://dig.chouti.com/')
print(response.text)

#2、帶參數的GET請求->params
#2.1自己拼接GET參數
#在請求頭內將自己偽裝成瀏覽器,否則百度不會正常返回頁面內容
import requests
response=requests.get('https://www.baidu.com/s?wd=python&pn=1',
                      headers={
                        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
                      })
print(response.text)


#如果查詢關鍵詞是中文或者有其他特殊符號,則不得不進行url編碼
from urllib.parse import urlencode
wd='egon老師'
encode_res=urlencode({'k':wd},encoding='utf-8')
keyword=encode_res.split('=')[1]
print(keyword)
# 然后拼接成url
url='https://www.baidu.com/s?wd=%s&pn=1' %keyword

response=requests.get(url,
                      headers={
                        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
                      })
res1=response.text

#2.2params參數的使用
#上述操作可以用requests模塊的一個params參數搞定,本質還是調用urlencode
from urllib.parse import urlencode
wd='egon老師'
pn=1

response=requests.get('https://www.baidu.com/s',
                      params={
                          'wd':wd,
                          'pn':pn
                      },
                      headers={
                        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
                      })
res2=response.text

#驗證結果,打開a.html與b.html頁面內容一樣
with open('a.html','w',encoding='utf-8') as f:
    f.write(res1)
with open('b.html', 'w', encoding='utf-8') as f:
    f.write(res2)

#3、帶參數的GET請求->headers
"""
#通常我們在發送請求時都需要帶上請求頭,請求頭是將自身偽裝成瀏覽器的關鍵,常見的有用的請求頭如下
Host
Referer #大型網站通常都會根據該參數判斷請求的來源
User-Agent #客戶端
Cookie #Cookie信息雖然包含在請求頭里,但requests模塊有單獨的參數來處理他,headers={}內就不要放它了
"""
#添加headers(瀏覽器會識別請求頭,不加可能會被拒絕訪問,比如訪問https://www.zhihu.com/explore)
import requests
response=requests.get('https://www.zhihu.com/explore')
response.status_code #500

#自己定制headers
headers={
    'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36',

}
respone=requests.get('https://www.zhihu.com/explore',
                     headers=headers)
print(respone.status_code) #200


#4、帶參數的GET請求->cookies
#登錄github,然后從瀏覽器中獲取cookies,以后就可以直接拿着cookie登錄了,無需輸入用戶名密碼
#用戶名:egonlin 郵箱378533872@qq.com 密碼lhf@123

import requests

Cookies={   'user_session':'wGMHFJKgDcmRIVvcA14_Wrt_3xaUyJNsBnPbYzEL6L0bHcfc',
}

response=requests.get('https://github.com/settings/emails',
             cookies=Cookies) #github對請求頭沒有什么限制,我們無需定制user-agent,對於其他網站可能還需要定制


print('378533872@qq.com' in response.text) #True
View Code

二、基於POST請求

  • 數據不會出現在地址欄中
  • 數據的大小沒有上限
  • 有請求體
  • 請求體中如果存在中文,會使用URL編碼!
  • requests.post()用法與requests.get()完全一致,特殊的是requests.post()有一個data參數,用來存放請求體數據
"""
發送post請求,模擬瀏覽器的登錄行為
對於登錄來說,應該輸錯用戶名或密碼然后分析抓包流程,輸對了瀏覽器就跳轉了,就找不到包
自動登錄github(自己處理cookie信息)
"""
'''
一 目標站點分析
    瀏覽器輸入https://github.com/login
    然后輸入錯誤的賬號密碼,抓包
    發現登錄行為是post提交到:https://github.com/session
    而且請求頭包含cookie
    而且請求體包含:
        commit:Sign in
        utf8:...
        authenticity_token:lbI8IJCwGslZS8qJPnof5e7ZkCoSoMn6jmDTsL1r/m06NLyIbw7vCrpwrFAPzHMep3Tmf/TSJVoXWrvDZaVwxQ==
        login:egonlin
        password:123


二 流程分析
    先GET:https://github.com/login拿到初始cookie與authenticity_token
    返回POST:https://github.com/session, 帶上初始cookie,帶上請求體(authenticity_token,用戶名,密碼等)
    最后拿到登錄cookie

    ps:如果密碼時密文形式,則可以先輸錯賬號,輸對密碼,然后到瀏覽器中拿到加密后的密碼,github的密碼是明文
'''

import requests
import re

#第一次請求
r1=requests.get('https://github.com/login')
r1_cookie=r1.cookies.get_dict() #拿到初始cookie(未被授權)
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #從頁面中拿到CSRF TOKEN

#第二次請求:帶着初始cookie和TOKEN發送POST請求給登錄頁面,帶上賬號密碼
data={
    'commit':'Sign in',
    'utf8':'?',
    'authenticity_token':authenticity_token,
    'login':'317828332@qq.com',
    'password':'alex3714'
}
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie
             )


login_cookie=r2.cookies.get_dict()


#第三次請求:以后的登錄,拿着login_cookie就可以,比如訪問一些個人配置
r3=requests.get('https://github.com/settings/emails',
                cookies=login_cookie)

print('317828332@qq.com' in r3.text) #True




"""
#requests.session()自動幫我們保存cookie信息

補充:
requests.post(url='xxxxxxxx',
              data={'xxx':'yyy'}) #沒有指定請求頭,#默認的請求頭:application/x-www-form-urlencoed

#如果我們自定義請求頭是application/json,並且用data傳值, 則服務端取不到值
requests.post(url='',
              data={'':1,},
              headers={
                  'content-type':'application/json'
              })


requests.post(url='',
              json={'':1,},
              ) #默認的請求頭:application/json

"""
import requests
import re

session=requests.session()
#第一次請求
r1=session.get('https://github.com/login')
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #從頁面中拿到CSRF TOKEN

#第二次請求
data={
    'commit':'Sign in',
    'utf8':'?',
    'authenticity_token':authenticity_token,
    'login':'317828332@qq.com',
    'password':'alex3714'
}
r2=session.post('https://github.com/session',
             data=data,
             )

#第三次請求
r3=session.get('https://github.com/settings/emails')

print('317828332@qq.com' in r3.text) #True
View Code

三、響應Response

#1、response屬性
import requests
respone=requests.get('http://www.jianshu.com')
# respone屬性
print(respone.text)
print(respone.content)

print(respone.status_code)
print(respone.headers)
print(respone.cookies)
print(respone.cookies.get_dict())
print(respone.cookies.items())

print(respone.url)
print(respone.history)

print(respone.encoding)

#關閉:response.close()
from contextlib import closing
with closing(requests.get('xxx',stream=True)) as response:
    for line in response.iter_content():
    pass


#2、編碼問題
import requests
response=requests.get('http://www.autohome.com/news')
# response.encoding='gbk' #汽車之家網站返回的頁面內容為gb2312編碼的,而requests的默認編碼為ISO-8859-1,如果不設置成gbk則中文亂碼
print(response.text)


#3、獲取二進制數據
import requests

response=requests.get('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1509868306530&di=712e4ef3ab258b36e9f4b48e85a81c9d&imgtype=0&src=http%3A%2F%2Fc.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F11385343fbf2b211e1fb58a1c08065380dd78e0c.jpg')

with open('a.jpg','wb') as f:
    f.write(response.content)


#3.1獲取二進制流
#stream參數:一點一點的取,比如下載視頻時,如果視頻100G,用response.content然后一下子寫到文件中是不合理的

import requests

response=requests.get('https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo-transcode/1767502_56ec685f9c7ec542eeaf6eac93a65dc7_6fe25cd1347c_3.mp4',
                      stream=True)

with open('b.mp4','wb') as f:
    for line in response.iter_content():
        f.write(line)


#4、解析json
#解析json
import requests
response=requests.get('http://httpbin.org/get')

import json
res1=json.loads(response.text) #太麻煩

res2=response.json() #直接獲取json數據

print(res1 == res2) #True


#5、Redirection and History
#官網的解釋
響應Response
By default Requests will perform location redirection for all verbs except HEAD.

We can use the history property of the Response object to track redirection.

The Response.history list contains the Response objects that were created in order to complete the request. The list is sorted from the oldest to the most recent response.

For example, GitHub redirects all HTTP requests to HTTPS:

>>> r = requests.get('http://github.com')

>>> r.url
'https://github.com/'

>>> r.status_code
200

>>> r.history
[<Response [301]>]
If you're using GET, OPTIONS, POST, PUT, PATCH or DELETE, you can disable redirection handling with the allow_redirects parameter:

>>> r = requests.get('http://github.com', allow_redirects=False)

>>> r.status_code
301

>>> r.history
[]
If you're using HEAD, you can enable redirection as well:

>>> r = requests.head('http://github.com', allow_redirects=True)

>>> r.url
'https://github.com/'

>>> r.history
[<Response [301]>]
Redirection and History官網的解釋
import requests
import re

#第一次請求
r1=requests.get('https://github.com/login')
r1_cookie=r1.cookies.get_dict() #拿到初始cookie(未被授權)
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #從頁面中拿到CSRF TOKEN

#第二次請求:帶着初始cookie和TOKEN發送POST請求給登錄頁面,帶上賬號密碼
data={
    'commit':'Sign in',
    'utf8':'?',
    'authenticity_token':authenticity_token,
    'login':'317828332@qq.com',
    'password':'alex3714'
}






#測試一:沒有指定allow_redirects=False,則響應頭中出現Location就跳轉到新頁面,r2代表新頁面的response
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie
             )

print(r2.status_code) #200
print(r2.url) #看到的是跳轉后的頁面
print(r2.history) #看到的是跳轉前的response
print(r2.history[0].text) #看到的是跳轉前的response.text


#測試二:指定allow_redirects=False,則響應頭中即便出現Location也不會跳轉到新頁面,r2代表的仍然是老頁面的response
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie,
             allow_redirects=False
             )


print(r2.status_code) #302
print(r2.url) #看到的是跳轉前的頁面https://github.com/session
print(r2.history) #[]

利用github登錄后跳轉到主頁面的例子來驗證它
View Code

四、高級用法

#1、SSL Cert Verification

#證書驗證(大部分網站都是https)
import requests
respone=requests.get('https://www.12306.cn') #如果是ssl請求,首先檢查證書是否合法,不合法則報錯,程序終端


#改進1:去掉報錯,但是會報警告
import requests
respone=requests.get('https://www.12306.cn',verify=False) #不驗證證書,報警告,返回200
print(respone.status_code)


#改進2:去掉報錯,並且去掉警報信息
import requests
from requests.packages import urllib3
urllib3.disable_warnings() #關閉警告
respone=requests.get('https://www.12306.cn',verify=False)
print(respone.status_code)

#改進3:加上證書
#很多網站都是https,但是不用證書也可以訪問,大多數情況都是可以攜帶也可以不攜帶證書
#知乎\百度等都是可帶可不帶
#有硬性要求的,則必須帶,比如對於定向的用戶,拿到證書后才有權限訪問某個特定網站
import requests
respone=requests.get('https://www.12306.cn',
                     cert=('/path/server.crt',
                           '/path/key'))
print(respone.status_code)


#2、使用代理
#官網鏈接: http://docs.python-requests.org/en/master/user/advanced/#proxies

#代理設置:先發送請求給代理,然后由代理幫忙發送(封ip是常見的事情)
import requests
proxies={
    'http':'http://egon:123@localhost:9743',#帶用戶名密碼的代理,@符號前是用戶名與密碼
    'http':'http://localhost:9743',
    'https':'https://localhost:9743',
}
respone=requests.get('https://www.12306.cn',
                     proxies=proxies)

print(respone.status_code)



#支持socks代理,安裝:pip install requests[socks]
import requests
proxies = {
    'http': 'socks5://user:pass@host:port',
    'https': 'socks5://user:pass@host:port'
}
respone=requests.get('https://www.12306.cn',
                     proxies=proxies)

print(respone.status_code)


#3、超時設置
#超時設置
#兩種超時:float or tuple
#timeout=0.1 #代表接收數據的超時時間
#timeout=(0.1,0.2)#0.1代表鏈接超時  0.2代表接收數據的超時時間

import requests
respone=requests.get('https://www.baidu.com',
                     timeout=0.0001)


#4、 認證設置

#官網鏈接:http://docs.python-requests.org/en/master/user/authentication/

#認證設置:登陸網站是,彈出一個框,要求你輸入用戶名密碼(與alter很類似),此時是無法獲取html的
# 但本質原理是拼接成請求頭發送
#         r.headers['Authorization'] = _basic_auth_str(self.username, self.password)
# 一般的網站都不用默認的加密方式,都是自己寫
# 那么我們就需要按照網站的加密方式,自己寫一個類似於_basic_auth_str的方法
# 得到加密字符串后添加到請求頭
#         r.headers['Authorization'] =func('.....')

#看一看默認的加密方式吧,通常網站都不會用默認的加密設置
import requests
from requests.auth import HTTPBasicAuth
r=requests.get('xxx',auth=HTTPBasicAuth('user','password'))
print(r.status_code)

#HTTPBasicAuth可以簡寫為如下格式
import requests
r=requests.get('xxx',auth=('user','password'))
print(r.status_code)

#5、異常處理

#異常處理
import requests
from requests.exceptions import * #可以查看requests.exceptions獲取異常類型

try:
    r=requests.get('http://www.baidu.com',timeout=0.00001)
except ReadTimeout:
    print('===:')
# except ConnectionError: #網絡不通
#     print('-----')
# except Timeout:
#     print('aaaaa')

except RequestException:
    print('Error')


#6、上傳文件
import requests
files={'file':open('a.jpg','rb')}
respone=requests.post('http://httpbin.org/post',files=files)
print(respone.status_code)
View Code

selenium

  • 官網點擊
  • selenium最初是一個自動化測試工具,而爬蟲中使用它主要是為了解決requests無法直接執行JavaScript代碼的問題
  • selenium本質是通過驅動瀏覽器,完全模擬瀏覽器的操作,比如跳轉、輸入、點擊、下拉等,來拿到網頁渲染之后的結果,可支持多種瀏覽器
  • PhantomJS是一款無界面的瀏覽器,其自動化操作流程和上述操作谷歌瀏覽器是一致的。由於是無界面的,為了能夠展示自動化操作流程,PhantomJS為用戶提供了一個截屏的功能,使用save_screenshot函數實現。
  • selenium+phantomjs 就是爬蟲終極解決方案:有些網站上的內容信息是通過動態加載js形成的,所以使用普通爬蟲程序無法回去動態加載的js內容。
  • 由於PhantomJs最近已經停止了更新和維護,所以推薦大家可以使用谷歌的無頭瀏覽器,是一款無界面的谷歌瀏覽器。

一、環境搭建

  • 安裝selenium:pip install selenium
  • 獲取某一款瀏覽器的驅動程序(以谷歌瀏覽器為例)谷歌瀏覽器驅動下載地址:http://chromedriver.storage.googleapis.com/index.html
  • 下載的驅動程序必須和瀏覽器的版本統一,大家可以根據http://blog.csdn.net/huilan_same/article/details/51896672中提供的版本映射表進行對應
"""
selenium模塊的基本使用

問題:selenium模塊和爬蟲之間具有怎樣的關聯?
    - 便捷的獲取網站中動態加載的數據
    - 便捷實現模擬登錄
什么是selenium模塊?
    - 基於瀏覽器自動化的一個模塊。

selenium使用流程:
    - 環境安裝:pip install selenium
    - 下載一個瀏覽器的驅動程序(谷歌瀏覽器)
        - 下載路徑:http://chromedriver.storage.googleapis.com/index.html
        - 驅動程序和瀏覽器的映射關系:http://blog.csdn.net/huilan_same/article/details/51896672
    - 實例化一個瀏覽器對象
    - 編寫基於瀏覽器自動化的操作代碼
        - 發起請求:get(url)
        - 標簽定位:find系列的方法
        - 標簽交互:send_keys('xxx')
        - 執行js程序:excute_script('jsCode')
        - 前進,后退:back(),forward()
        - 關閉瀏覽器:quit()

    - selenium處理iframe
        - 如果定位的標簽存在於iframe標簽之中,則必須使用switch_to.frame(id)
        - 動作鏈(拖動):from selenium.webdriver import ActionChains
            - 實例化一個動作鏈對象:action = ActionChains(bro)
            - click_and_hold(div):長按且點擊操作
            - move_by_offset(x,y)
            - perform()讓動作鏈立即執行
            - action.release()釋放動作鏈對象

12306模擬登錄
    - 超級鷹:http://www.chaojiying.com/about.html
        - 注冊:普通用戶
        - 登錄:普通用戶
            - 題分查詢:充值
            - 創建一個軟件(id)
            - 下載示例代碼

    - 12306模擬登錄編碼流程:
        - 使用selenium打開登錄頁面
        - 對當前selenium打開的這張頁面進行截圖
        - 對當前圖片局部區域(驗證碼圖片)進行裁剪
            - 好處:將驗證碼圖片和模擬登錄進行一一對應。
        - 使用超級鷹識別驗證碼圖片(坐標)
        - 使用動作鏈根據坐標實現點擊操作
        - 錄入用戶名密碼,點擊登錄按鈕實現登錄

"""

################################################################
from selenium import webdriver
from time import sleep
# 后面是你的瀏覽器驅動位置,記得前面加r'','r'是防止字符轉義的
driver = webdriver.Chrome(r'./chromedriver.exe')
# 用get打開百度頁面
driver.get("http://www.baidu.com")
# 查找頁面的“設置”選項,並進行點擊
driver.find_elements_by_link_text('設置')[0].click()
sleep(10)
# # 打開設置后找到“搜索設置”選項,設置為每頁顯示50條
driver.find_elements_by_link_text('搜索設置')[0].click()
sleep(10)
# 選中每頁顯示50條
m = driver.find_element_by_id('nr')
sleep(10)
m.find_element_by_xpath('//*[@id="nr"]/option[3]').click()
m.find_element_by_xpath('.//option[3]').click()
sleep(10)
# 點擊保存設置
driver.find_elements_by_class_name("prefpanelgo")[0].click()
sleep(10)
# 處理彈出的警告頁面   確定accept() 和 取消dismiss()
driver.switch_to_alert().accept()
sleep(10)
# 找到百度的輸入框,並輸入 美女
driver.find_element_by_id('kw').send_keys('美女')
sleep(10)
# 點擊搜索按鈕
driver.find_element_by_id('su').click()
sleep(10)
# 在打開的頁面中找到“Selenium - 開源中國社區”,並打開這個頁面
driver.find_elements_by_link_text('美女_百度圖片')[0].click()
sleep(10)
# 關閉瀏覽器
driver.quit()
################################################################
from selenium import webdriver
from lxml import etree
from time import sleep
#實例化一個瀏覽器對象(傳入瀏覽器的驅動成)
bro = webdriver.Chrome(executable_path='./chromedriver.exe')
#讓瀏覽器發起一個指定url對應請求
bro.get('http://125.35.6.84:81/xk/')

#page_source獲取瀏覽器當前頁面的頁面源碼數據
page_text = bro.page_source

#解析企業名稱
tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@id="gzlist"]/li')
for li in li_list:
    name = li.xpath('./dl/@title')[0]
    print(name)
sleep(5)
bro.quit()

################################################################

from selenium import webdriver
from time import sleep
bro = webdriver.Chrome(executable_path='./chromedriver.exe')

bro.get('https://www.taobao.com/')

#標簽定位
search_input = bro.find_element_by_id('q')
#標簽交互
search_input.send_keys('Iphone')

#執行一組js程序
bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(2)
#點擊搜索按鈕
btn = bro.find_element_by_css_selector('.btn-search')
btn.click()
bro.get('https://www.baidu.com')
sleep(2)
#回退
bro.back()
sleep(2)
#前進
bro.forward()
sleep(5)
#退出
bro.quit()

#############################動作鏈和iframe的處理###################################

from selenium import webdriver
from time import sleep
#導入動作鏈對應的類
from selenium.webdriver import ActionChains
bro = webdriver.Chrome(executable_path='./chromedriver')

bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')

#如果定位的標簽是存在於iframe標簽之中的則必須通過如下操作在進行標簽定位
bro.switch_to.frame('iframeResult')#切換瀏覽器標簽定位的作用域
div = bro.find_element_by_id('draggable')

#動作鏈
action = ActionChains(bro)
#點擊長按指定的標簽
action.click_and_hold(div)

for i in range(5):
    #perform()立即執行動作鏈操作
    #move_by_offset(x,y):x水平方向 y豎直方向
    action.move_by_offset(17,0).perform()
    sleep(0.5)

#釋放動作鏈
action.release()
bro.quit()

#############################模擬登錄qq空間###################################
from selenium import webdriver
from time import sleep

bro = webdriver.Chrome(executable_path='./chromedriver')

bro.get('https://qzone.qq.com/')

bro.switch_to.frame('login_frame')

a_tag = bro.find_element_by_id("switcher_plogin")
a_tag.click()


userName_tag = bro.find_element_by_id('u')
password_tag = bro.find_element_by_id('p')
sleep(1)
userName_tag.send_keys('328410948')
sleep(1)
password_tag.send_keys('123456789')
sleep(1)
btn = bro.find_element_by_id('login_button')
btn.click()

sleep(3)

bro.quit()

############################谷歌無頭瀏覽器+反檢測#####################################

from selenium import webdriver
from time import sleep
#實現無可視化界面
from selenium.webdriver.chrome.options import Options
#實現規避檢測
from selenium.webdriver import ChromeOptions

#實現無可視化界面的操作
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

#實現規避檢測
option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])

#如何實現讓selenium規避被檢測到的風險
bro = webdriver.Chrome(executable_path='./chromedriver',chrome_options=chrome_options,options=option)

#無可視化界面(無頭瀏覽器) phantomJs
bro.get('https://www.baidu.com')

print(bro.page_source)
sleep(2)
bro.quit()
基本使用
#下述代碼為超級鷹提供的示例代碼
import requests
from hashlib import md5

class Chaojiying_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; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }

    def PostPic(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)
        return r.json()

    def ReportError(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)
        return r.json()

# chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370')    #用戶中心>>軟件ID 生成一個替換 96001
# im = open('12306.jpg', 'rb').read()                                                    #本地圖片文件路徑 來替換 a.jpg 有時WIN系統須要//
# print(chaojiying.PostPic(im, 9004)['pic_str'])
#上述代碼為超級鷹提供的示例代碼

#使用selenium打開登錄頁面
from selenium import webdriver
import time
from PIL import Image
from selenium.webdriver import ActionChains
bro = webdriver.Chrome(executable_path='./chromedriver')
bro.get('https://kyfw.12306.cn/otn/login/init')
time.sleep(1)

#save_screenshot就是將當前頁面進行截圖且保存
bro.save_screenshot('aa.png')

#確定驗證碼圖片對應的左上角和右下角的坐標(裁剪的區域就確定)
code_img_ele = bro.find_element_by_xpath('//*[@id="loginForm"]/div/ul[2]/li[4]/div/div/div[3]/img')
location = code_img_ele.location  # 驗證碼圖片左上角的坐標 x,y
print('location:',location)
size = code_img_ele.size  #驗證碼標簽對應的長和寬
print('size:',size)
#左上角和右下角坐標
rangle = (
int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height']))
#至此驗證碼圖片區域就確定下來了

i = Image.open('./aa.png')
code_img_name = './code.png'
#crop根據指定區域進行圖片裁剪
frame = i.crop(rangle)
frame.save(code_img_name)

#將驗證碼圖片提交給超級鷹進行識別
chaojiying = Chaojiying_Client('bobo328410948', 'bobo328410948', '899370')    #用戶中心>>軟件ID 生成一個替換 96001
im = open('code.png', 'rb').read()                                                    #本地圖片文件路徑 來替換 a.jpg 有時WIN系統須要//
print(chaojiying.PostPic(im, 9004)['pic_str'])
result = chaojiying.PostPic(im, 9004)['pic_str']
all_list = [] #要存儲即將被點擊的點的坐標  [[x1,y1],[x2,y2]]
if '|' in result:
    list_1 = result.split('|')
    count_1 = len(list_1)
    for i in range(count_1):
        xy_list = []
        x = int(list_1[i].split(',')[0])
        y = int(list_1[i].split(',')[1])
        xy_list.append(x)
        xy_list.append(y)
        all_list.append(xy_list)
else:
    x = int(result.split(',')[0])
    y = int(result.split(',')[1])
    xy_list = []
    xy_list.append(x)
    xy_list.append(y)
    all_list.append(xy_list)
print(all_list)
#遍歷列表,使用動作鏈對每一個列表元素對應的x,y指定的位置進行點擊操作
for l in all_list:
    x = l[0]
    y = l[1]
    ActionChains(bro).move_to_element_with_offset(code_img_ele, x, y).click().perform()
    time.sleep(0.5)

bro.find_element_by_id('username').send_keys('www.zhangbowudi@qq.com')
time.sleep(2)
bro.find_element_by_id('password').send_keys('bobo_15027900535')
time.sleep(2)
bro.find_element_by_id('loginSub').click()
time.sleep(30)
bro.quit()
模擬登陸

二、圖片懶加載

  • 圖片懶加載是一種網頁優化技術。圖片作為一種網絡資源,在被請求時也與普通靜態資源一樣,將占用網絡資源,而一次性將整個頁面的所有圖片加載完,將大大增加頁面的首屏加載時間。為了解決這種問題,通過前后端配合,使圖片僅在瀏覽器當前視窗內出現時才加載該圖片,達到減少首屏圖片請求數的技術就被稱為“圖片懶加載”。
  • 在網頁源碼中,在img標簽中首先會使用一個“偽屬性”(通常使用src2,original......)去存放真正的圖片鏈接而並非是直接存放在src屬性中。當圖片出現到頁面的可視化區域中,會動態將偽屬性替換成src屬性,完成圖片的加載。
"""
問題:處理頁面動態加載數據的爬取
1.selenium
2.phantomJs

1.selenum:三方庫。可以實現讓瀏覽器完成自動化的操作。
2.環境搭建
2.1 安裝:pip install selenium
2.2 獲取瀏覽器的驅動程序
下載地址:http://chromedriver.storage.googleapis.com/index.html
瀏覽器版本和驅動版本的對應關系表: https://blog.csdn.net/huilan_same/article/details/51896672

#使用下面的方法,查找指定的元素進行操作即可
    find_element_by_id            根據id找節點
    find_elements_by_name         根據name找
    find_elements_by_xpath        根據xpath查找
    find_elements_by_tag_name     根據標簽名找
    find_elements_by_class_name   根據class名字查找


"""

#編碼流程:
from selenium import webdriver
from time import sleep
#創建一個瀏覽器對象executable_path驅動的路徑
bro = webdriver.Chrome(executable_path='./chromedriver')
#get方法可以指定一個url,讓瀏覽器進行請求
bro.get('https://www.baidu.com')
sleep(1)
#讓百度進行指定詞條的一個搜索
text = bro.find_element_by_id('kw')#定位到了text文本框
text.send_keys('人民幣') #send_keys表示向文本框中錄入指定內容
sleep(1)
button = bro.find_element_by_id('su')
button.click()#click表示的是點擊操作
sleep(3)
bro.quit()#關閉瀏覽器

"""
phantomJs:無界面瀏覽器。其自動化流程上述操作谷歌自動化流程一致。
"""
from selenium import webdriver
bro = webdriver.PhantomJS(executable_path='/Users/bobo/Desktop/路飛爬蟲授課/動態數據加載爬取/phantomjs-2.1.1-macosx/bin/phantomjs')
#打開瀏覽器
bro.get('https://www.baidu.com')
#截屏
bro.save_screenshot('./1.png')
text = bro.find_element_by_id('kw')#定位到了text文本框
text.send_keys('人民幣') #send_keys表示向文本框中錄入指定內容
bro.save_screenshot('./2.png')
bro.quit()

"""
使用selenium+phantomJs處理頁面動態加載數據的爬取
需求:獲取豆瓣電影中動態加載出更多電影詳情數據
"""
from selenium import webdriver
from time import sleep
bro = webdriver.PhantomJS(executable_path='/Users/bobo/Desktop/路飛爬蟲授課/動態數據加載爬取/phantomjs-2.1.1-macosx/bin/phantomjs')
url = 'https://movie.douban.com/typerank?type_name=%E5%96%9C%E5%89%A7&type=24&interval_id=100:90&action='
bro.get(url)
sleep(1)
#截屏
bro.save_screenshot('./1.png')
#編寫js代碼:讓頁面中的滾輪向下滑動(底部)
js = 'window.scrollTo(0,document.body.scrollHeight)'
#如何讓瀏覽器對象執行js代碼
bro.execute_script(js)
sleep(1)
#截屏
bro.save_screenshot('./2.png')

bro.execute_script(js)
bro.save_screenshot('./3.png')
#獲取加載數據后的頁面:page_sourse獲取瀏覽器當前的頁面數據
page_text = bro.page_source
print(page_text)
基本使用
"""
selenium
"""
from selenium import webdriver
from time import sleep

# 后面是你的瀏覽器驅動位置,記得前面加r'','r'是防止字符轉義的
driver = webdriver.Chrome(r'驅動程序路徑')
# 用get打開百度頁面
driver.get("http://www.baidu.com")
# 查找頁面的“設置”選項,並進行點擊
driver.find_elements_by_link_text('設置')[0].click()
sleep(2)
# # 打開設置后找到“搜索設置”選項,設置為每頁顯示50條
driver.find_elements_by_link_text('搜索設置')[0].click()
sleep(2)

# 選中每頁顯示50條
m = driver.find_element_by_id('nr')
sleep(2)
m.find_element_by_xpath('//*[@id="nr"]/option[3]').click()
m.find_element_by_xpath('.//option[3]').click()
sleep(2)

# 點擊保存設置
driver.find_elements_by_class_name("prefpanelgo")[0].click()
sleep(2)

# 處理彈出的警告頁面   確定accept() 和 取消dismiss()
driver.switch_to_alert().accept()
sleep(2)
# 找到百度的輸入框,並輸入 美女
driver.find_element_by_id('kw').send_keys('美女')
sleep(2)
# 點擊搜索按鈕
driver.find_element_by_id('su').click()
sleep(2)
# 在打開的頁面中找到“Selenium - 開源中國社區”,並打開這個頁面
driver.find_elements_by_link_text('美女_百度圖片')[0].click()
sleep(3)

# 關閉瀏覽器
driver.quit()

"""
phantomJs
"""
from selenium import webdriver
import time
# phantomjs路徑
path = r'PhantomJS驅動路徑'
browser = webdriver.PhantomJS(path)
# 打開百度
url = 'http://www.baidu.com/'
browser.get(url)
time.sleep(3)
#截屏
browser.save_screenshot(r'phantomjs\baidu.png')
# 查找input輸入框
my_input = browser.find_element_by_id('kw')
# 往框里面寫文字
my_input.send_keys('美女')
time.sleep(3)
#截屏
browser.save_screenshot(r'phantomjs\meinv.png')
# 查找搜索按鈕
button = browser.find_elements_by_class_name('s_btn')[0]
button.click()
time.sleep(3)
browser.save_screenshot(r'phantomjs\show.png')
time.sleep(3)
browser.quit()

"""
selenium+phantomjs
"""
from selenium import webdriver
import time

if __name__ == '__main__':
    url = 'https://movie.douban.com/typerank?type_name=%E6%81%90%E6%80%96&type=20&interval_id=100:90&action='
    # 發起請求前,可以讓url表示的頁面動態加載出更多的數據
    path = r'C:\Users\Administrator\Desktop\爬蟲授課\day05\ziliao\phantomjs-2.1.1-windows\bin\phantomjs.exe'
    # 創建無界面的瀏覽器對象
    bro = webdriver.PhantomJS(path)
    # 發起url請求
    bro.get(url)
    time.sleep(3)
    # 截圖
    bro.save_screenshot('1.png')
    # 執行js代碼(讓滾動條向下偏移n個像素(作用:動態加載了更多的電影信息))
    js = 'window.scrollTo(0,document.body.scrollHeight)'
    bro.execute_script(js)  # 該函數可以執行一組字符串形式的js代碼
    time.sleep(2)
    bro.execute_script(js)  # 該函數可以執行一組字符串形式的js代碼
    time.sleep(2)
    bro.save_screenshot('2.png')
    time.sleep(2)
    # 使用爬蟲程序爬去當前url中的內容
    html_source = bro.page_source # 該屬性可以獲取當前瀏覽器的當前頁的源碼(html)
    with open('./source.html', 'w', encoding='utf-8') as fp:
        fp.write(html_source)
    bro.quit()


"""
谷歌無頭瀏覽器
"""
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time
# 創建一個參數對象,用來控制chrome以無界面模式打開
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
# 驅動路徑
path = r'C:\Users\ZBLi\Desktop\1801\day05\ziliao\chromedriver.exe'
# 創建瀏覽器對象
browser = webdriver.Chrome(executable_path=path, chrome_options=chrome_options)
# 上網
url = 'http://www.baidu.com/'
browser.get(url)
time.sleep(3)
browser.save_screenshot('baidu.png')
browser.quit()
selenium
from selenium import webdriver
browser=webdriver.Chrome()
browser=webdriver.Firefox()
browser=webdriver.PhantomJS()
browser=webdriver.Safari()
browser=webdriver.Edge() 
瀏覽器對象
"""
1、有界面瀏覽器 selenium+chromedriver

#安裝:selenium+chromedriver
pip3 install selenium
下載chromdriver.exe放到python安裝路徑的scripts目錄中即可,注意最新版本是2.38,並非2.9
國內鏡像網站地址:http://npm.taobao.org/mirrors/chromedriver/2.38/
最新的版本去官網找:https://sites.google.com/a/chromium.org/chromedriver/downloads

#驗證安裝
C:\Users\Administrator>python3
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from selenium import webdriver
>>> driver=webdriver.Chrome() #彈出瀏覽器
>>> driver.get('https://www.baidu.com')
>>> driver.page_source

#注意:
selenium3默認支持的webdriver是Firfox,而Firefox需要安裝geckodriver
下載鏈接:https://github.com/mozilla/geckodriver/releases
"""


"""
2、無界面瀏覽器selenium+phantomjs

PhantomJS不再更新
在 PhantomJS 年久失修, 后繼無人的節骨眼 
Chrome 出來救場, 再次成為了反爬蟲 Team 的噩夢
自Google 發布 chrome 59 / 60 正式版 開始便支持Headless mode 
這意味着在無 GUI 環境下, PhantomJS 不再是唯一選擇 

#安裝:selenium+phantomjs
pip3 install selenium
下載phantomjs,解壓后把phantomjs.exe所在的bin目錄放到環境變量
下載鏈接:http://phantomjs.org/download.html

#驗證安裝
C:\Users\Administrator>phantomjs
phantomjs> console.log('egon gaga')
egon gaga
undefined
phantomjs> ^C
C:\Users\Administrator>python3
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from selenium import webdriver
>>> driver=webdriver.PhantomJS() #無界面瀏覽器
>>> driver.get('https://www.baidu.com')
>>> driver.page_source

"""

"""
selenium+谷歌瀏覽器headless模式


#selenium:3.12.0
#webdriver:2.38
#chrome.exe: 65.0.3325.181(正式版本) (32 位)

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('window-size=1920x3000') #指定瀏覽器分辨率
chrome_options.add_argument('--disable-gpu') #谷歌文檔提到需要加上這個屬性來規避bug
chrome_options.add_argument('--hide-scrollbars') #隱藏滾動條, 應對一些特殊頁面
chrome_options.add_argument('blink-settings=imagesEnabled=false') #不加載圖片, 提升速度
chrome_options.add_argument('--headless') #瀏覽器不提供可視化頁面. linux下如果系統不支持可視化不加這條會啟動失敗
chrome_options.binary_location = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" #手動指定使用的瀏覽器位置


driver=webdriver.Chrome(chrome_options=chrome_options)
driver.get('https://www.baidu.com')

print('hao123' in driver.page_source)


driver.close() #切記關閉瀏覽器,回收資源

"""
安裝
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待頁面加載某些元素

browser=webdriver.Chrome()
try:
    browser.get('https://www.baidu.com')

    input_tag=browser.find_element_by_id('kw')
    input_tag.send_keys('美女') #python2中輸入中文錯誤,字符串前加個u
    input_tag.send_keys(Keys.ENTER) #輸入回車

    wait=WebDriverWait(browser,10)
    wait.until(EC.presence_of_element_located((By.ID,'content_left'))) #等到id為content_left的元素加載完畢,最多等10秒

    print(browser.page_source)
    print(browser.current_url)
    print(browser.get_cookies())

finally:
    browser.close()
使用

三、選擇器

1、基本用法

#官網鏈接:http://selenium-python.readthedocs.io/locating-elements.html
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待頁面加載某些元素
import time

driver=webdriver.Chrome()
driver.get('https://www.baidu.com')
wait=WebDriverWait(driver,10)

try:
    #===============所有方法===================
    # 1、find_element_by_id
    # 2、find_element_by_link_text
    # 3、find_element_by_partial_link_text
    # 4、find_element_by_tag_name
    # 5、find_element_by_class_name
    # 6、find_element_by_name
    # 7、find_element_by_css_selector
    # 8、find_element_by_xpath
    # 強調:
    # 1、上述均可以改寫成find_element(By.ID,'kw')的形式
    # 2、find_elements_by_xxx的形式是查找到多個元素,結果為列表

    #===============示范用法===================
    # 1、find_element_by_id
    print(driver.find_element_by_id('kw'))

    # 2、find_element_by_link_text
    # login=driver.find_element_by_link_text('登錄')
    # login.click()

    # 3、find_element_by_partial_link_text
    login=driver.find_elements_by_partial_link_text('')[0]
    login.click()

    # 4、find_element_by_tag_name
    print(driver.find_element_by_tag_name('a'))

    # 5、find_element_by_class_name
    button=wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'tang-pass-footerBarULogin')))
    button.click()

    # 6、find_element_by_name
    input_user=wait.until(EC.presence_of_element_located((By.NAME,'userName')))
    input_pwd=wait.until(EC.presence_of_element_located((By.NAME,'password')))
    commit=wait.until(EC.element_to_be_clickable((By.ID,'TANGRAM__PSP_10__submit')))

    input_user.send_keys('18611453110')
    input_pwd.send_keys('xxxxxx')
    commit.click()

    # 7、find_element_by_css_selector
    driver.find_element_by_css_selector('#kw')

    # 8、find_element_by_xpath

    time.sleep(5)

finally:
    driver.close()
View Code

2、xpath

#官網鏈接:http://selenium-python.readthedocs.io/locating-elements.html
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待頁面加載某些元素
import time

driver=webdriver.PhantomJS()
driver.get('https://doc.scrapy.org/en/latest/_static/selectors-sample1.html')
# wait=WebDriverWait(driver,3)
driver.implicitly_wait(3) #使用隱式等待

try:
    # find_element_by_xpath
    #//與/
    # driver.find_element_by_xpath('//body/a')  # 開頭的//代表從整篇文檔中尋找,body之后的/代表body的兒子,這一行找不到就會報錯了

    driver.find_element_by_xpath('//body//a')  # 開頭的//代表從整篇文檔中尋找,body之后的//代表body的子子孫孫
    driver.find_element_by_css_selector('body a')

    #取第n個
    res1=driver.find_elements_by_xpath('//body//a[1]') #取第一個a標簽
    print(res1[0].text)

    #按照屬性查找,下述三者查找效果一樣
    res1=driver.find_element_by_xpath('//a[5]')
    res2=driver.find_element_by_xpath('//a[@href="image5.html"]')
    res3=driver.find_element_by_xpath('//a[contains(@href,"image5")]') #模糊查找
    print('==>', res1.text)
    print('==>',res2.text)
    print('==>',res3.text)


    #其他
    res1=driver.find_element_by_xpath('/html/body/div/a')
    print(res1.text)

    res2=driver.find_element_by_xpath('//a[img/@src="image3_thumb.jpg"]') #找到子標簽img的src屬性為image3_thumb.jpg的a標簽
    print(res2.tag_name,res2.text)

    res3 = driver.find_element_by_xpath("//input[@name='continue'][@type='button']") #查看屬性name為continue且屬性type為button的input標簽
    res4 = driver.find_element_by_xpath("//*[@name='continue'][@type='button']") #查看屬性name為continue且屬性type為button的所有標簽
    
    
    time.sleep(5)

finally:
    driver.close()
View Code

3、獲取標簽屬性

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待頁面加載某些元素

browser=webdriver.Chrome()

browser.get('https://www.amazon.cn/')

wait=WebDriverWait(browser,10)
wait.until(EC.presence_of_element_located((By.ID,'cc-lm-tcgShowImgContainer')))

tag=browser.find_element(By.CSS_SELECTOR,'#cc-lm-tcgShowImgContainer img')

#獲取標簽屬性,
print(tag.get_attribute('src'))


#獲取標簽ID,位置,名稱,大小(了解)
print(tag.id)
print(tag.location)
print(tag.tag_name)
print(tag.size)


browser.close()
獲取標簽屬性

四、等待元素被加載

"""
#1、selenium只是模擬瀏覽器的行為,而瀏覽器解析頁面是需要時間的(執行css,js),一些元素可能需要過一段時間才能加載出來,為了保證能查找到元素,必須等待

#2、等待的方式分兩種:
隱式等待:在browser.get('xxx')前就設置,針對所有元素有效
顯式等待:在browser.get('xxx')之后設置,只針對某個元素有效
"""
#隱式等待
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待頁面加載某些元素

browser=webdriver.Chrome()

#隱式等待:在查找所有元素時,如果尚未被加載,則等10秒
browser.implicitly_wait(10)

browser.get('https://www.baidu.com')


input_tag=browser.find_element_by_id('kw')
input_tag.send_keys('美女')
input_tag.send_keys(Keys.ENTER)

contents=browser.find_element_by_id('content_left') #沒有等待環節而直接查找,找不到則會報錯
print(contents)

browser.close()


#顯式等待
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待頁面加載某些元素

browser=webdriver.Chrome()
browser.get('https://www.baidu.com')


input_tag=browser.find_element_by_id('kw')
input_tag.send_keys('美女')
input_tag.send_keys(Keys.ENTER)


#顯式等待:顯式地等待某個元素被加載
wait=WebDriverWait(browser,10)
wait.until(EC.presence_of_element_located((By.ID,'content_left')))

contents=browser.find_element(By.CSS_SELECTOR,'#content_left')
print(contents)


browser.close()
View Code

五、元素交互操作

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待頁面加載某些元素

browser=webdriver.Chrome()
browser.get('https://www.amazon.cn/')
wait=WebDriverWait(browser,10)


input_tag=wait.until(EC.presence_of_element_located((By.ID,'twotabsearchtextbox')))
input_tag.send_keys('iphone 8')
button=browser.find_element_by_css_selector('#nav-search > form > div.nav-right > div > input')
button.click()


import time
time.sleep(3)

input_tag=browser.find_element_by_id('twotabsearchtextbox')
input_tag.clear() #清空輸入框
input_tag.send_keys('iphone7plus')
button=browser.find_element_by_css_selector('#nav-search > form > div.nav-right > div > input')
button.click()



# browser.close()
點擊,清空
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By  # 按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys  # 鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait  # 等待頁面加載某些元素
import time

driver = webdriver.Chrome()
driver.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
wait=WebDriverWait(driver,3)
# driver.implicitly_wait(3)  # 使用隱式等待

try:
    driver.switch_to.frame('iframeResult') ##切換到iframeResult
    sourse=driver.find_element_by_id('draggable')
    target=driver.find_element_by_id('droppable')

    #方式一:基於同一個動作鏈串行執行
    # actions=ActionChains(driver) #拿到動作鏈對象
    # actions.drag_and_drop(sourse,target) #把動作放到動作鏈中,准備串行執行
    # actions.perform()

    #方式二:不同的動作鏈,每次移動的位移都不同
    ActionChains(driver).click_and_hold(sourse).perform()
    distance=target.location['x']-sourse.location['x']

    track=0
    while track < distance:
        ActionChains(driver).move_by_offset(xoffset=2,yoffset=0).perform()
        track+=2

    ActionChains(driver).release().perform()

    time.sleep(10)

finally:
    driver.close()
Action Chains
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待頁面加載某些元素


try:
    browser=webdriver.Chrome()
    browser.get('https://www.baidu.com')
    browser.execute_script('alert("hello world")') #打印警告
finally:
    browser.close()
在交互動作比較難實現的時候可以自己寫JS(萬能方法)
#frame相當於一個單獨的網頁,在父frame里是無法直接查看到子frame的元素的,必須switch_to_frame切到該frame下,才能進一步查找

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待頁面加載某些元素


try:
    browser=webdriver.Chrome()
    browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')

    browser.switch_to.frame('iframeResult') #切換到id為iframeResult的frame

    tag1=browser.find_element_by_id('droppable')
    print(tag1)

    # tag2=browser.find_element_by_id('textareaCode') #報錯,在子frame里無法查看到父frame的元素
    browser.switch_to.parent_frame() #切回父frame,就可以查找到了
    tag2=browser.find_element_by_id('textareaCode')
    print(tag2)

finally:
    browser.close()
補充:frame的切換

六、其他

#模擬瀏覽器的前進后退
import time
from selenium import webdriver

browser=webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.get('https://www.taobao.com')
browser.get('http://www.sina.com.cn/')

browser.back()
time.sleep(10)
browser.forward()
browser.close()
模擬瀏覽器的前進后退
#cookies
from selenium import webdriver

browser=webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())
browser.add_cookie({'k1':'xxx','k2':'yyy'})
print(browser.get_cookies())

# browser.delete_all_cookies()
cookies
#選項卡管理:切換選項卡,有js的方式windows.open,有windows快捷鍵:ctrl+t等,最通用的就是js的方式
import time
from selenium import webdriver

browser=webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.execute_script('window.open()')

print(browser.window_handles) #獲取所有的選項卡
browser.switch_to_window(browser.window_handles[1])
browser.get('https://www.taobao.com')
time.sleep(10)
browser.switch_to_window(browser.window_handles[0])
browser.get('https://www.sina.com.cn')
browser.close()
選項卡管理
from selenium import webdriver
from selenium.common.exceptions import TimeoutException,NoSuchElementException,NoSuchFrameException

try:
    browser=webdriver.Chrome()
    browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
    browser.switch_to.frame('iframssseResult')

except TimeoutException as e:
    print(e)
except NoSuchFrameException as e:
    print(e)
finally:
    browser.close()
異常處理
#注意:網站都策略都是在不斷變化的,精髓在於學習流程。下述代碼生效與2017-11-7,不能保證永久有效
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

browser=webdriver.Chrome()

try:
    browser.get('http://mail.163.com/')

    wait=WebDriverWait(browser,5)

    frame=wait.until(EC.presence_of_element_located((By.ID,'x-URS-iframe')))
    browser.switch_to.frame(frame)

    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'.m-container')))

    inp_user=browser.find_element_by_name('email')
    inp_pwd=browser.find_element_by_name('password')
    button=browser.find_element_by_id('dologin')
    inp_user.send_keys('18611453110')
    inp_pwd.send_keys('xxxx')
    button.click()

    #如果遇到驗證碼,可以把下面一小段打開注釋
    # import time
    # time.sleep(10)
    # button = browser.find_element_by_id('dologin')
    # button.click()

    wait.until(EC.presence_of_element_located((By.ID,'dvNavTop')))
    write_msg=browser.find_elements_by_css_selector('#dvNavTop li')[1] #獲取第二個li標簽就是“寫信”了
    write_msg.click()


    wait.until(EC.presence_of_element_located((By.CLASS_NAME,'tH0')))
    recv_man=browser.find_element_by_class_name('nui-editableAddr-ipt')
    title=browser.find_element_by_css_selector('.dG0 .nui-ipt-input')
    recv_man.send_keys('378533872@qq.com')
    title.send_keys('聖旨')
    print(title.tag_name)


    frame=wait.until(EC.presence_of_element_located((By.CLASS_NAME,'APP-editor-iframe')))
    browser.switch_to.frame(frame)
    body=browser.find_element(By.CSS_SELECTOR,'body')
    body.send_keys('egon很帥,可以加工資了')

    browser.switch_to.parent_frame() #切回他爹
    send_button=browser.find_element_by_class_name('nui-toolbar-item')
    send_button.click()

    #可以睡時間久一點別讓瀏覽器關掉,看看發送成功沒有
    import time
    time.sleep(10000)

except Exception as e:
    print(e)
finally:
    browser.close()
自動登錄163郵箱並發送郵件
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #鍵盤按鍵操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待頁面加載某些元素
import time


def get_goods(driver):
    try:
        goods=driver.find_elements_by_class_name('gl-item')

        for good in goods:
            detail_url=good.find_element_by_tag_name('a').get_attribute('href')

            p_name=good.find_element_by_css_selector('.p-name em').text.replace('\n','')
            price=good.find_element_by_css_selector('.p-price i').text
            p_commit=good.find_element_by_css_selector('.p-commit a').text

            msg = '''
            商品 : %s
            鏈接 : %s
            價錢 :%s
            評論 :%s
            ''' % (p_name,detail_url,price,p_commit)

            print(msg,end='\n\n')


        button=driver.find_element_by_partial_link_text('下一頁')
        button.click()
        time.sleep(1)
        get_goods(driver)
    except Exception:
        pass

def spider(url,keyword):
    driver = webdriver.Chrome()
    driver.get(url)
    driver.implicitly_wait(3)  # 使用隱式等待
    try:
        input_tag=driver.find_element_by_id('key')
        input_tag.send_keys(keyword)
        input_tag.send_keys(Keys.ENTER)
        get_goods(driver)
    finally:
        driver.close()


if __name__ == '__main__':
    spider('https://www.jd.com/',keyword='iPhone8手機')
爬取京東商城商品信息

驗證碼處理

  • 簡單的校驗碼Tesserocr就可以搞定
  • 極驗滑動認證 極驗官網:http://www.geetest.com/
"""
雲打碼平台(打碼兔)處理驗證碼的實現流程:
- 1.對攜帶驗證碼的頁面數據進行抓取
- 2.可以將頁面數據中驗證碼進行解析,驗證碼圖片下載到本地
- 3.可以將驗證碼圖片提交給三方平台進行識別,返回驗證碼圖片上的數據值
    - 雲打碼平台:
        - 1.在官網中進行注冊(普通用戶和開發者用戶)
        - 2.登錄開發者用戶:
            - 1.實例代碼的下載(開發文檔-》調用實例及最新的DLL-》PythonHTTP實例下載)
            - 2.創建一個軟件:我的軟件-》添加新的軟件
        -3.使用示例代碼中的源碼文件中的代碼進行修改,讓其識別驗證碼圖片中的數據值
"""
import http.client, mimetypes, urllib, json, time, requests
class YDMHttp:
    apiurl = 'http://api.yundama.com/api.php'
    username = ''
    password = ''
    appid = ''
    appkey = ''

    def __init__(self, username, password, appid, appkey):
        self.username = username
        self.password = password
        self.appid = str(appid)
        self.appkey = appkey

    def request(self, fields, files=[]):
        response = self.post_url(self.apiurl, fields, files)
        response = json.loads(response)
        return response

    def balance(self):
        data = {'method': 'balance', 'username': self.username, 'password': self.password, 'appid': self.appid,
                'appkey': self.appkey}
        response = self.request(data)
        if (response):
            if (response['ret'] and response['ret'] < 0):
                return response['ret']
            else:
                return response['balance']
        else:
            return -9001

    def login(self):
        data = {'method': 'login', 'username': self.username, 'password': self.password, 'appid': self.appid,
                'appkey': self.appkey}
        response = self.request(data)
        if (response):
            if (response['ret'] and response['ret'] < 0):
                return response['ret']
            else:
                return response['uid']
        else:
            return -9001

    def upload(self, filename, codetype, timeout):
        data = {'method': 'upload', 'username': self.username, 'password': self.password, 'appid': self.appid,
                'appkey': self.appkey, 'codetype': str(codetype), 'timeout': str(timeout)}
        file = {'file': filename}
        response = self.request(data, file)
        if (response):
            if (response['ret'] and response['ret'] < 0):
                return response['ret']
            else:
                return response['cid']
        else:
            return -9001

    def result(self, cid):
        data = {'method': 'result', 'username': self.username, 'password': self.password, 'appid': self.appid,
                'appkey': self.appkey, 'cid': str(cid)}
        response = self.request(data)
        return response and response['text'] or ''

    def decode(self, filename, codetype, timeout):
        cid = self.upload(filename, codetype, timeout)
        if (cid > 0):
            for i in range(0, timeout):
                result = self.result(cid)
                if (result != ''):
                    return cid, result
                else:
                    time.sleep(1)
            return -3003, ''
        else:
            return cid, ''

    def report(self, cid):
        data = {'method': 'report', 'username': self.username, 'password': self.password, 'appid': self.appid,
                'appkey': self.appkey, 'cid': str(cid), 'flag': '0'}
        response = self.request(data)
        if (response):
            return response['ret']
        else:
            return -9001

    def post_url(self, url, fields, files=[]):
        for key in files:
            files[key] = open(files[key], 'rb');
        res = requests.post(url, files=files, data=fields)
        return res.text



# 該函數就調用了打碼平台的相關的接口對指定的驗證碼圖片進行識別,返回圖片上的數據值
def getCode(codeImg):
    # 雲打碼平台普通用戶的用戶名
    username = 'bobo328410948'
    # 雲打碼平台普通用戶的密碼
    password = 'bobo328410948'
    # 軟件ID,開發者分成必要參數。登錄開發者后台【我的軟件】獲得!
    appid = 6003
    # 軟件密鑰,開發者分成必要參數。登錄開發者后台【我的軟件】獲得!
    appkey = '1f4b564483ae5c907a1d34f8e2f2776c'
    # 驗證碼圖片文件
    filename = codeImg
    # 驗證碼類型,# 例:1004表示4位字母數字,不同類型收費不同。請准確填寫,否則影響識別率。在此查詢所有類型 http://www.yundama.com/price.html
    codetype = 3000
    # 超時時間,秒
    timeout = 20
    # 檢查
    if (username == 'username'):
        print('請設置好相關參數再測試')
    else:
        # 初始化
        yundama = YDMHttp(username, password, appid, appkey)
        # 登陸雲打碼
        uid = yundama.login();
        print('uid: %s' % uid)
        # 查詢余額
        balance = yundama.balance();
        print('balance: %s' % balance)
        # 開始識別,圖片路徑,驗證碼類型ID,超時時間(秒),識別結果
        cid, result = yundama.decode(filename, codetype, timeout);
        print('cid: %s, result: %s' % (cid, result))
        return result


##
import requests
from lxml import etree
import json
import time
import re
#1.對攜帶驗證碼的頁面數據進行抓取
url = 'https://www.douban.com/accounts/login?source=movie'
headers = {
    'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Mobile Safari/537.36'
}
page_text = requests.get(url=url,headers=headers).text

#2.可以將頁面數據中驗證碼進行解析,驗證碼圖片下載到本地
tree = etree.HTML(page_text)
codeImg_url = tree.xpath('//*[@id="captcha_image"]/@src')[0]
#獲取了驗證碼圖片對應的二進制數據值
code_img = requests.get(url=codeImg_url,headers=headers).content


#獲取capture_id
'<img id="captcha_image" src="https://www.douban.com/misc/captcha?id=AdC4WXGyiRuVJrP9q15mqIrt:en&amp;size=s" alt="captcha" class="captcha_image">'
c_id = re.findall('<img id="captcha_image".*?id=(.*?)&amp.*?>',page_text,re.S)[0]
with open('./code.png','wb') as fp:
    fp.write(code_img)

#獲得了驗證碼圖片上面的數據值
codeText = getCode('./code.png')
print(codeText)
#進行登錄操作
post = 'https://accounts.douban.com/login'
data = {
    "source": "movie",
    "redir": "https://movie.douban.com/",
    "form_email": "15027900535",
    "form_password": "bobo@15027900535",
    "captcha-solution":codeText,
    "captcha-id":c_id,
    "login": "登錄",
}
print(c_id)
login_text = requests.post(url=post,data=data,headers=headers).text
with open('./login.html','w',encoding='utf-8') as fp:
    fp.write(login_text)
雲打碼
#步驟一:點擊按鈕,彈出沒有缺口的圖片

#步驟二:獲取步驟一的圖片

#步驟三:點擊滑動按鈕,彈出帶缺口的圖片

#步驟四:獲取帶缺口的圖片

#步驟五:對比兩張圖片的所有RBG像素點,得到不一樣像素點的x值,即要移動的距離

#步驟六:模擬人的行為習慣(先勻加速拖動后勻減速拖動),把需要拖動的總距離分成一段一段小的軌跡

#步驟七:按照軌跡拖動,完全驗證

#步驟八:完成登錄

#安裝:selenium+chrome/phantomjs

#安裝:Pillow
Pillow:基於PIL,處理python 3.x的圖形圖像庫.因為PIL只能處理到python 2.x,而這個模塊能處理Python3.x,目前用它做圖形的很多.
http://www.cnblogs.com/apexchu/p/4231041.html

C:\Users\Administrator>pip3 install pillow
C:\Users\Administrator>python3
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from PIL import Image
極驗步驟
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PIL import Image
import time

def get_snap():
    '''
    對整個網頁截圖,保存成圖片,然后用PIL.Image拿到圖片對象
    :return: 圖片對象
    '''
    driver.save_screenshot('snap.png')
    page_snap_obj=Image.open('snap.png')
    return page_snap_obj

def get_image():
    '''
    從網頁的網站截圖中,截取驗證碼圖片
    :return: 驗證碼圖片
    '''
    img=wait.until(EC.presence_of_element_located((By.CLASS_NAME,'geetest_canvas_img')))
    time.sleep(2) #保證圖片刷新出來
    localtion=img.location
    size=img.size

    top=localtion['y']
    bottom=localtion['y']+size['height']
    left=localtion['x']
    right=localtion['x']+size['width']

    page_snap_obj=get_snap()
    crop_imag_obj=page_snap_obj.crop((left,top,right,bottom))
    return crop_imag_obj


def get_distance(image1,image2):
    '''
    拿到滑動驗證碼需要移動的距離
    :param image1:沒有缺口的圖片對象
    :param image2:帶缺口的圖片對象
    :return:需要移動的距離
    '''
    threshold=60
    left=57
    for i in range(left,image1.size[0]):
        for j in range(image1.size[1]):
            rgb1=image1.load()[i,j]
            rgb2=image2.load()[i,j]
            res1=abs(rgb1[0]-rgb2[0])
            res2=abs(rgb1[1]-rgb2[1])
            res3=abs(rgb1[2]-rgb2[2])
            if not (res1 < threshold and res2 < threshold and res3 < threshold):
                return i-7 #經過測試,誤差為大概為7
    return i-7 #經過測試,誤差為大概為7


def get_tracks(distance):
    '''
    拿到移動軌跡,模仿人的滑動行為,先勻加速后勻減速
    勻變速運動基本公式:
    ①v=v0+at
    ②s=v0t+½at²
    ③v²-v0²=2as

    :param distance: 需要移動的距離
    :return: 存放每0.3秒移動的距離
    '''
    #初速度
    v=0
    #單位時間為0.2s來統計軌跡,軌跡即0.2內的位移
    t=0.3
    #位移/軌跡列表,列表內的一個元素代表0.2s的位移
    tracks=[]
    #當前的位移
    current=0
    #到達mid值開始減速
    mid=distance*4/5

    while current < distance:
        if current < mid:
            # 加速度越小,單位時間的位移越小,模擬的軌跡就越多越詳細
            a= 2
        else:
            a=-3

        #初速度
        v0=v
        #0.2秒時間內的位移
        s=v0*t+0.5*a*(t**2)
        #當前的位置
        current+=s
        #添加到軌跡列表
        tracks.append(round(s))

        #速度已經達到v,該速度作為下次的初速度
        v=v0+a*t
    return tracks


try:
    driver=webdriver.Chrome()
    driver.get('https://account.geetest.com/login')
    wait=WebDriverWait(driver,10)

    #步驟一:先點擊按鈕,彈出沒有缺口的圖片
    button=wait.until(EC.presence_of_element_located((By.CLASS_NAME,'geetest_radar_tip')))
    button.click()

    #步驟二:拿到沒有缺口的圖片
    image1=get_image()

    #步驟三:點擊拖動按鈕,彈出有缺口的圖片
    button=wait.until(EC.presence_of_element_located((By.CLASS_NAME,'geetest_slider_button')))
    button.click()

    #步驟四:拿到有缺口的圖片
    image2=get_image()

    # print(image1,image1.size)
    # print(image2,image2.size)

    #步驟五:對比兩張圖片的所有RBG像素點,得到不一樣像素點的x值,即要移動的距離
    distance=get_distance(image1,image2)

    #步驟六:模擬人的行為習慣(先勻加速拖動后勻減速拖動),把需要拖動的總距離分成一段一段小的軌跡
    tracks=get_tracks(distance)
    print(tracks)
    print(image1.size)
    print(distance,sum(tracks))


    #步驟七:按照軌跡拖動,完全驗證
    button=wait.until(EC.presence_of_element_located((By.CLASS_NAME,'geetest_slider_button')))
    ActionChains(driver).click_and_hold(button).perform()
    for track in tracks:
        ActionChains(driver).move_by_offset(xoffset=track,yoffset=0).perform()
    else:
        ActionChains(driver).move_by_offset(xoffset=3,yoffset=0).perform() #先移過一點
        ActionChains(driver).move_by_offset(xoffset=-3,yoffset=0).perform() #再退回來,是不是更像人了

    time.sleep(0.5) #0.5秒后釋放鼠標
    ActionChains(driver).release().perform()


    #步驟八:完成登錄
    input_email=driver.find_element_by_id('email')
    input_password=driver.find_element_by_id('password')
    button=wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'login-btn')))

    input_email.send_keys('18611453110@163.com')
    input_password.send_keys('linhaifeng123')
    # button.send_keys(Keys.ENTER)
    button.click()

    import time
    time.sleep(200)
finally:
    driver.close()
View Code
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PIL import Image
import time

def get_snap():
    driver.save_screenshot('full_snap.png')
    page_snap_obj=Image.open('full_snap.png')
    return page_snap_obj

def get_image():
    img=driver.find_element_by_class_name('geetest_canvas_img')
    time.sleep(2)
    location=img.location
    size=img.size

    left=location['x']
    top=location['y']
    right=left+size['width']
    bottom=top+size['height']

    page_snap_obj=get_snap()
    image_obj=page_snap_obj.crop((left,top,right,bottom))
    # image_obj.show()
    return image_obj

def get_distance(image1,image2):
    start=57
    threhold=60

    for i in range(start,image1.size[0]):
        for j in range(image1.size[1]):
            rgb1=image1.load()[i,j]
            rgb2=image2.load()[i,j]
            res1=abs(rgb1[0]-rgb2[0])
            res2=abs(rgb1[1]-rgb2[1])
            res3=abs(rgb1[2]-rgb2[2])
            # print(res1,res2,res3)
            if not (res1 < threhold and res2 < threhold and res3 < threhold):
                return i-7
    return i-7

def get_tracks(distance):
    distance+=20 #先滑過一點,最后再反着滑動回來
    v=0
    t=0.2
    forward_tracks=[]

    current=0
    mid=distance*3/5
    while current < distance:
        if current < mid:
            a=2
        else:
            a=-3

        s=v*t+0.5*a*(t**2)
        v=v+a*t
        current+=s
        forward_tracks.append(round(s))

    #反着滑動到准確位置
    back_tracks=[-3,-3,-2,-2,-2,-2,-2,-1,-1,-1] #總共等於-20

    return {'forward_tracks':forward_tracks,'back_tracks':back_tracks}

try:
    # 1、輸入賬號密碼回車
    driver = webdriver.Chrome()
    driver.implicitly_wait(3)
    driver.get('https://passport.cnblogs.com/user/signin')

    username = driver.find_element_by_id('input1')
    pwd = driver.find_element_by_id('input2')
    signin = driver.find_element_by_id('signin')

    username.send_keys('linhaifeng')
    pwd.send_keys('xxxxx')
    signin.click()

    # 2、點擊按鈕,得到沒有缺口的圖片
    button = driver.find_element_by_class_name('geetest_radar_tip')
    button.click()

    # 3、獲取沒有缺口的圖片
    image1 = get_image()

    # 4、點擊滑動按鈕,得到有缺口的圖片
    button = driver.find_element_by_class_name('geetest_slider_button')
    button.click()

    # 5、獲取有缺口的圖片
    image2 = get_image()

    # 6、對比兩種圖片的像素點,找出位移
    distance = get_distance(image1, image2)

    # 7、模擬人的行為習慣,根據總位移得到行為軌跡
    tracks = get_tracks(distance)
    print(tracks)

    # 8、按照行動軌跡先正向滑動,后反滑動
    button = driver.find_element_by_class_name('geetest_slider_button')
    ActionChains(driver).click_and_hold(button).perform()

    # 正常人類總是自信滿滿地開始正向滑動,自信地表現是瘋狂加速
    for track in tracks['forward_tracks']:
        ActionChains(driver).move_by_offset(xoffset=track, yoffset=0).perform()

    # 結果傻逼了,正常的人類停頓了一下,回過神來發現,卧槽,滑過了,然后開始反向滑動
    time.sleep(0.5)
    for back_track in tracks['back_tracks']:
        ActionChains(driver).move_by_offset(xoffset=back_track, yoffset=0).perform()

    # 小范圍震盪一下,進一步迷惑極驗后台,這一步可以極大地提高成功率
    ActionChains(driver).move_by_offset(xoffset=-3, yoffset=0).perform()
    ActionChains(driver).move_by_offset(xoffset=3, yoffset=0).perform()

    # 成功后,騷包人類總喜歡默默地欣賞一下自己拼圖的成果,然后戀戀不舍地松開那只臟手
    time.sleep(0.5)
    ActionChains(driver).release().perform()

    time.sleep(10)  # 睡時間長一點,確定登錄成功
finally:
    driver.close()
cnblog
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PIL import Image
import time

def get_snap(driver):
    driver.save_screenshot('full_snap.png')
    page_snap_obj=Image.open('full_snap.png')
    return page_snap_obj

def get_image(driver):
    img=driver.find_element_by_class_name('geetest_canvas_img')
    time.sleep(2)
    location=img.location
    size=img.size

    left=location['x']
    top=location['y']
    right=left+size['width']
    bottom=top+size['height']

    page_snap_obj=get_snap(driver)
    image_obj=page_snap_obj.crop((left,top,right,bottom))
    # image_obj.show()
    return image_obj

def get_distance(image1,image2):
    start=57
    threhold=60

    for i in range(start,image1.size[0]):
        for j in range(image1.size[1]):
            rgb1=image1.load()[i,j]
            rgb2=image2.load()[i,j]
            res1=abs(rgb1[0]-rgb2[0])
            res2=abs(rgb1[1]-rgb2[1])
            res3=abs(rgb1[2]-rgb2[2])
            # print(res1,res2,res3)
            if not (res1 < threhold and res2 < threhold and res3 < threhold):
                return i-7
    return i-7

def get_tracks(distance):
    distance+=20 #先滑過一點,最后再反着滑動回來
    v=0
    t=0.2
    forward_tracks=[]

    current=0
    mid=distance*3/5
    while current < distance:
        if current < mid:
            a=2
        else:
            a=-3

        s=v*t+0.5*a*(t**2)
        v=v+a*t
        current+=s
        forward_tracks.append(round(s))

    #反着滑動到准確位置
    back_tracks=[-3,-3,-2,-2,-2,-2,-2,-1,-1,-1] #總共等於-20

    return {'forward_tracks':forward_tracks,'back_tracks':back_tracks}

def crack(driver): #破解滑動認證
    # 1、點擊按鈕,得到沒有缺口的圖片
    button = driver.find_element_by_class_name('geetest_radar_tip')
    button.click()

    # 2、獲取沒有缺口的圖片
    image1 = get_image(driver)

    # 3、點擊滑動按鈕,得到有缺口的圖片
    button = driver.find_element_by_class_name('geetest_slider_button')
    button.click()

    # 4、獲取有缺口的圖片
    image2 = get_image(driver)

    # 5、對比兩種圖片的像素點,找出位移
    distance = get_distance(image1, image2)

    # 6、模擬人的行為習慣,根據總位移得到行為軌跡
    tracks = get_tracks(distance)
    print(tracks)

    # 7、按照行動軌跡先正向滑動,后反滑動
    button = driver.find_element_by_class_name('geetest_slider_button')
    ActionChains(driver).click_and_hold(button).perform()

    # 正常人類總是自信滿滿地開始正向滑動,自信地表現是瘋狂加速
    for track in tracks['forward_tracks']:
        ActionChains(driver).move_by_offset(xoffset=track, yoffset=0).perform()

    # 結果傻逼了,正常的人類停頓了一下,回過神來發現,卧槽,滑過了,然后開始反向滑動
    time.sleep(0.5)
    for back_track in tracks['back_tracks']:
        ActionChains(driver).move_by_offset(xoffset=back_track, yoffset=0).perform()

    # 小范圍震盪一下,進一步迷惑極驗后台,這一步可以極大地提高成功率
    ActionChains(driver).move_by_offset(xoffset=-3, yoffset=0).perform()
    ActionChains(driver).move_by_offset(xoffset=3, yoffset=0).perform()

    # 成功后,騷包人類總喜歡默默地欣賞一下自己拼圖的成果,然后戀戀不舍地松開那只臟手
    time.sleep(0.5)
    ActionChains(driver).release().perform()

def login_cnblogs(username,password):
    driver = webdriver.Chrome()
    try:
        # 1、輸入賬號密碼回車
        driver.implicitly_wait(3)
        driver.get('https://passport.cnblogs.com/user/signin')

        input_username = driver.find_element_by_id('input1')
        input_pwd = driver.find_element_by_id('input2')
        signin = driver.find_element_by_id('signin')

        input_username.send_keys(username)
        input_pwd.send_keys(password)
        signin.click()

        # 2、破解滑動認證
        crack(driver)

        time.sleep(10)  # 睡時間長一點,確定登錄成功
    finally:
        driver.close()

if __name__ == '__main__':
    login_cnblogs(username='linhaifeng',password='xxxx')
修訂版


免責聲明!

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



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