爬蟲基礎
爬蟲認知
是一種按照一定的規(guī)則,自動地抓取萬維網(wǎng)信息的程序或者腳本。通俗的講: 就是模擬客戶端發(fā)起網(wǎng)絡請求,接收請求的響應,按照一定的規(guī)則,自動的抓取互聯(lián)網(wǎng)信息的程序。
網(wǎng)絡請求
urllib庫
導入庫
from urllib import request
from urllib import parse
urlopen()函數(shù)
"""
urlopen()函數(shù):在urllib.request模塊中,用來網(wǎng)絡請求
參數(shù): 1.url:請求網(wǎng)站的url 2.data:請求的data提交的表單數(shù)據(jù)
返回值: 返回值是一個 http.client.HTTPResponse 對象,這個對象是一個類文件句柄對象。
有 read(size) 、 readline 、 readlines 以及 getcode 等方法。
"""
# respone = request.urlopen('http://www.baidu.com')
# print(respone.getcode())
urlretrieve() 函數(shù)
"""
urlretrieve() 函數(shù)的用法: 將網(wǎng)頁上的文件保存到本地
參數(shù):1.文件地址 2.要保存的文件名 + 后綴名
"""
# img_url = 'https://edu-image.nosdn.127.net/deaf24ba-2bd5-4266-8c65-a9a615fef61e.jpg?imageView&quality=100&crop=0_0_1080_680&thumbnail=450y250'
# request.urlretrieve(img_url,'21天搞定Python分布爬蟲.png')
urlencode()函數(shù)
"""
urlencode()函數(shù)用法: 發(fā)送請求時候,如果url中包含中文或者其他特殊字符,則需要進行路徑編碼
urlencode 可以把字典塑膠轉換成URL編碼的數(shù)據(jù)
"""
# params = {'name':'張三',"age":18,'greet':'hello world'}
# result = parse.urlencode(params)
# print(result)
# url = 'http://www.baidu.com/s'
# params = {"wd":"劉德華"}
# qs = parse.urlencode(params)
# url = url + "?" + qs
# resp = request.urlopen(url)
# print(resp.read())
parse_qs()函數(shù)
"""
parse_qs()函數(shù)用法: 講經(jīng)過編碼后的url參數(shù)進行解碼
"""
# params = {'name':'張三',"age":18,'greet':'hello world'}
# qs = parse.urlencode(params) # 編碼
# print(qs)
# restult = parse.parse_qs(qs) # 解碼
# print(restult)
#
urlparse() 和 urlsplit()函數(shù)
"""
urlparse() 和 urlsplit()函數(shù): 將URL中各個組成部分進行分割
區(qū)別: urlparse 里面多了一個 params 屬性,而 urlsplit 沒有這個 params 屬性。
"""
# url = 'http://www.baidu.com/s?username=zhiliao'
#
# result = parse.urlsplit(url)
# result2 = parse.urlparse(url)
#
# print('urlsplit: ',result)
# print('urlparse: ',result2)
#
# print('scheme: ',result.scheme)
# print('netloc ',result.netloc)
# print('path ',result.path)
# print('query ',result.query)
request.Request類
"""
request.Request類:
# 如果要在請求時候添加某些 請求信息(如:headers、data等 網(wǎng)絡請求必須要的參數(shù)),就需要 Request類進行封裝請求數(shù)據(jù)
# 類型轉換: str => bytes:encode() ; bytes => str:decode()
# Request:默認情況是 get()請求方法,但是只要傳了 data參數(shù),就是post()請求方法
"""
# from urllib import request,parse
#
# url = "https://music.163.com/weapi/cloudsearch/get/web?csrf_token="
# headers = {
# "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
# }
# formdata = {
# "params": "foUlX36kSAGPWtUp5SoqQTK9qDpJUuld45H57CYE49VM4zPJq8qwZxFwvL5djdWf61EFKPmFBZEzQ0wajuz1dE8a/pPKLciXET2mpGG3Pq1cWCMkOL1/kOSre2Qu0dHojZjHbHii/RbSNtmdIwVKbRD660wt8FBRRamrKbryU9NriJv5bLagmaFQ7aaOh5QQ6fjS2ENsAViwTVU58yvD85TWjS6zop28bhbLGePML4x3n8qaYIlAza4UNKaTAJ3wZNn7AdVP2FGbzD8NiSYjW/Wc+UwgsqWjsUU5wzmFf/Q=",
# "encSecKey": "32c74c08ae72ff1e5c39de0fb64b15b981d50f873a0afb73c4511939d67bc83fd101ed53f347798a10a86fb46cb55f651c1256413de44cd9ecc197c5cbd3eda58aa4075aeb2ca73b0fe4c6b23248200dc85b23f3206ab06e6e4568aa02219396b8203f886dc3fa08c2a7e2ff283eabf60e992bc10f7bafb9ab89ab8dd3b3a020"
# }
#
# req = request.Request(url=url,headers=headers,data=parse.urlencode(formdata).encode('utf-8'))
# resp = request.urlopen(req)
# print(resp.read().decode('utf-8'))
# from urllib import request
#
# headers = {
# "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
# "Referer": "https://www.qiushibaike.com/text/",
# "Origin": "https://www.qiushibaike.com"
# }
# req = request.Request("https://www.qiushibaike.com/text/page/2/",headers=headers)
# resp = request.urlopen(req)
# print(resp.read().decode('utf-8'))
ProxyHandler()代理處理器
"""
ProxyHandler處理器(代理設置):
訪問網(wǎng)站頻繁被識別為 爬蟲: 網(wǎng)站會檢測某一段時間某個IP的訪問次數(shù),如果訪問次數(shù)多的不像正常人,它會禁止這個IP的訪問。
可以通過IP代理服務器 進行 反爬; 自定義 opener()方法 來使用代理
"""
# from urllib import request
#
# ## 沒使用 IP代理情況
# # url = 'http://httpbin.org/ip'
# # resp = request.urlopen(url)
# # print(resp.read())
# ## 使用IP代理
# url = 'http://httpbin.org/ip'
# # 1. 使用ProxyHandler()方法,傳入代理傳教一個 handler
# handler = request.ProxyHandler({"118.113.245.100":"9999"}) # ProxyHandler()傳入一個字典:{"ip":"prot"}
# # 2.使用上面創(chuàng)建的handler 構建一個 opener 代理對象
# opener = request.build_opener(handler)
# # 3.使用 opener代理對象 發(fā)送請求
# resp = opener.open(url)
# print(resp.read())
ProxyHandler處理器 總結
"""
### ProxyHandler處理器(代理):
1. 代理的原理:在請求目的網(wǎng)站之前,先請求代理服務器,然后讓代理服務器去請求目的網(wǎng)站,
代理服務器拿到目的網(wǎng)站的數(shù)據(jù)后,再轉發(fā)給我們的代碼。
2. http://httpbin.org:這個網(wǎng)站可以方便的查看http請求的一些參數(shù)。
3. 在代碼中使用代理:
* 使用`urllib.request.ProxyHandler`,傳入一個代理,這個代理是一個字典,
字典的key依賴于代理服務器能夠接收的類型,一般是`http`或者`https`,值是`ip:port`。
* 使用上一步創(chuàng)建的`handler`,以及`request.build_opener`創(chuàng)建一個`opener`對象。
* 使用上一步創(chuàng)建的`opener`,調(diào)用`open`函數(shù),發(fā)起請求。
示例代碼如下:
```python
from urllib import request
url = 'http://httpbin.org/ip'
# 1. 使用ProxyHandler,傳入代理構建一個handler
handler = request.ProxyHandler({"http":"223.241.78.43:8010"})
# 2. 使用上面創(chuàng)建的handler構建一個opener
opener = request.build_opener(handler)
# 3. 使用opener去發(fā)送一個請求
resp = opener.open(url)
print(resp.read())
```
"""
Cookie技術
"""
網(wǎng)絡連接中,http協(xié)議是無狀態(tài)的、沒記憶:服務器與 客服端 無法進行識別;從而無法可持續(xù)進行數(shù)據(jù)傳輸、交互;
Cookie技術 :則是解決http傳輸協(xié)議的缺點,保存 服務器和客戶端 連接后的認證信息,讓兩者后續(xù) 進行有效的 連接、訪問、交流
"""
""" 保存 cookie 到本地,可以使用 cookiejar 的 save 方法,并且需要指定一個文件名: """
# from urllib import request
# from http.cookiejar import MozillaCookieJar
#
# headers = {
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/62.0.3202.94 Safari/537.36'
# }
#
# cookiejar = MozillaCookieJar("cookie.txt") # 生成 存儲 cookie的文件
# handler = request.HTTPCookieProcessor(cookiejar)
# opener = request.build_opener(handler)
#
# req = request.Request('http://httpbin.org/cookies',headers=headers)
# resp = opener.open(req)
#
# print(resp.read())
# cookiejar.save(ignore_discard=True,ignore_expires=True) # 保存 cookie
"""從本地加載 cookie ,需要使用 cookiejar 的 load 方法,并且也需要指定方法:"""
# from urllib import request
# from http.cookiejar import MozillaCookieJar
#
# headers = {
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/62.0.3202.94 Safari/537.36'
# }
#
# cookiejar = MozillaCookieJar('cookie.txt')
# cookiejar.load(ignore_discard=True) # 加載 cookie文件 信息
# handler = request.HTTPCookieProcessor(cookiejar)
# opener = request.build_opener(handler)
#
# resp = opener.open('http://httpbin.org/cookies')
# for cookie in cookiejar:
# print(cookie)
# 大鵬董成鵬主頁:http://www.renren.com/880151247/profile
# 人人網(wǎng)登錄url:http://www.renren.com/PLogin.do
"""1. 不使用cookie去請求大鵬的主頁 => 結果:請求失敗,需要登錄驗證;"""
from urllib import request
# dapeng_url = "http://www.renren.com/880151247/profile"
# headers = {
# 'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
# "Cookie":"anonymid=jacdwz2x-8bjldx; depovince=GW; _r01_=1; _ga=GA1.2.1455063316.1511436360; _gid=GA1.2.862627163.1511436360; wp=1; JSESSIONID=abcrs0queAwRp_sk9dS-v; ch_id=10016; jebecookies=c68b9b55-b6a1-4661-8d11-832862cfa246|||||; ick_login=7e3299f4-1e31-4455-b2a4-e5317c9e2ccf; _de=EA5778F44555C091303554EBBEB4676C696BF75400CE19CC; p=a96969b7912d80d95127b7935c1b729e1; first_login_flag=1; ln_uact=970138074@qq.com; ln_hurl=http://hdn.xnimg.cn/photos/hdn121/20170428/1700/main_nhiB_aebd0000854a1986.jpg; t=4d2ccb81ee83a6b1d3925b94779d22e21; societyguester=4d2ccb81ee83a6b1d3925b94779d22e21; id=443362311; xnsid=13bf03ea; loginfrom=syshome; jebe_key=9c062f5a-4335-4a91-bf7a-970f8b86a64e%7Ca022c303305d1b2ab6b5089643e4b5de%7C1511449232839%7C1; wp_fold=0"
# }
# req = request.Request(url=dapeng_url,headers=headers)
# resp = request.urlopen(req)
# with open('renren.html','w',encoding='utf-8') as fp:
# # write函數(shù)必須寫入一個str的數(shù)據(jù)類型
# # resp.read()讀出來的是一個bytes數(shù)據(jù)類型
# # bytes -> decode -> str
# # str -> encode -> bytes
# fp.write(resp.read().decode('utf-8'))
# 大鵬董成鵬主頁:http://www.renren.com/880151247/profile
# 人人網(wǎng)登錄url:http://www.renren.com/PLogin.do
"""2. 使用cookie去請求大鵬的主頁 => 結果:請求成功,返回對應信息"""
from urllib import request
from urllib import parse
from http.cookiejar import CookieJar
headers = {
'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
}
# 創(chuàng)建 共享的請求對象,保存驗證信息
def get_opener():
cookiejar = CookieJar() # 創(chuàng)建 cookiejar 對象
handler = request.HTTPCookieProcessor(cookiejar) # 創(chuàng)建一個 HTTPCookieProcessor() HttpCookie處理器對象
opener = request.build_opener(handler) # 創(chuàng)建一個 攜帶cookie信息的 opener()請求對象
return opener
# 登錄,并獲取登錄信息
def login_renren(opener):
# 1.使用opener發(fā)送登錄的請求(人人網(wǎng)的郵箱和密碼)
data = {
'email':"970138074@qq.com",
'password': "pythonspider"
}
login_url = "http://www.renren.com/PLogin.do"
req = request.Request(login_url,data=parse.urlencode(data).encode('utf-8'),headers=headers)
response = opener.open(req)
print(response.read().decode("utf-8"))
# 使用已登錄信息,進行訪問主頁
def visit_profile(opener):
# 2. 訪問個人主頁
dapeng_url = "http://www.renren.com/880151247/profile"
# 獲取個人主頁的頁面的時候,不要新建一個opener;而應該使用之前的那個opener,
# 因為之前的那個opener已經(jīng)包含了登錄所需要的cookie信息
req = request.Request(dapeng_url,headers=headers)
resp = opener.open(req)
with open('abc.html','w',encoding='utf-8') as fp:
fp.write(resp.read().decode('utf-8'))
if __name__ == '__main__':
opener = get_opener()
login_renren(opener)
visit_profile(opener)
requests庫
requests庫
"""
requests庫:
雖然Python的標準庫中 urllib模塊已經(jīng)包含了平常我們使用的大多數(shù)功能,但是它的 API 使用起來
讓人感覺不太好,而 Requests宣傳是 “HTTP for Humans”,說明使用更簡潔方便。
"""
# import requests
#
# # 最簡單的發(fā)送 get 請求就是通過 requests.get 來調(diào)用
# response = requests.get("https://www.baidu.com/") # params 接收一個字典或者字符串的查詢參數(shù),字典類型自動轉換為url編碼,不需要urlencode()
# print(type(response.text)) #
# print(response.text) #查看響應內(nèi)容,response.text 返回的是Unicode格式的數(shù)據(jù)
# print(type(response.content)) #
# print(response.content) # 查看響應內(nèi)容,response.content返回的字節(jié)流數(shù)據(jù)
# print(response.content.decode('utf-8')) #
#
# print(response.url) # # 查看完整url地址
# print(response.encoding) #查看響應頭部字符編碼
# print(response.status_code) # 查看響應碼
發(fā)送GET請求
## 1. params 傳入 參數(shù)形式:
# import requests
#
# params = {
# 'wd': '中國'
# }
# headers = {
# 'User-Agent': 'ozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
# }
# response = requests.get("https://www.baidu.com/s",params=params,headers=headers)
#
# with open('baidu.html','w',encoding='utf-8') as fp:
# fp.write(response.content.decode('utf-8'))
#
# print(response.url)
發(fā)送POST請求
## 2. data 傳入 表單數(shù)據(jù) 形式:
# import requests
#
# url = 'https://www.lagou.com/jobs/positionAjax.json?city=%E6%B7%B1%E5%9C%B3&needAddtionalResult=false&isSchoolJob=0'
#
# data = {
# 'first':"true",
# 'pn': '1',
# 'kd': 'python'
# }
# headers = {
# 'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=',
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
# }
#
# response = requests.post(url,data=data,headers=headers)
# print(type(response.json()))
# print(response.json())
proxies代理
## 3. proxies 傳入 代理服務器 形式:
# import requests
#
# proxy = {
# 'http': '182.148.206.83:9999'
# }
#
# response = requests.get("http://httpbin.org/ip",proxies=proxy)
# print(response.text)
verify 處理不信任
## 4. verify 處理不信任的SSL證書 形式:
# import requests
#
# url = 'http://www.12306.cn/mormhweb/'
# resp = requests.get(url,verify=True)
# with open('12306.html','w',encoding='utf-8') as fp:
# fp.write(resp.text)
cookie
## 5. cookie:如果在一個響應中包含了 cookie ,返回的 cookie 值: 形式:
# import requests
# url = "http://www.renren.com/PLogin.do"
# data = {"email":"970138074@qq.com",'password':"pythonspider"}
# resp = requests.get('http://www.baidu.com/')
# print(resp.cookies)
# print(resp.cookies.get_dict())
session
## 6. session: 保存會話信息并 共享 cookie數(shù)據(jù) 形式:
import requests
# response = requests.get('https://www.baidu.com/')
# print(response.cookies.get_dict())
# url = "http://www.renren.com/PLogin.do"
# data = {"email":"970138074@qq.com",'password':"pythonspider"}
# headers = {
# 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
# }
#
# session = requests.Session()
#
# session.post(url,data=data,headers=headers) # 先提交數(shù)據(jù),通過驗證
#
# response = session.get('http://www.renren.com/880151247/profile') # 再訪問主頁
# with open('renren.html','w',encoding='utf-8') as fp:
# fp.write(response.text)
request 和 session 小案例
import requests
def renren():
url = "http://www.renren.com/PLogin.do"
data = {"email": "970138074@qq.com", 'password': "pythonspider"}
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
}
# 登錄
session = requests.session()
session.post(url, data=data, headers=headers)
# 訪問大鵬個人中心
resp = session.get('http://www.renren.com/880151247/profile')
print(resp.text)
requests筆記
## 發(fā)送get請求:
發(fā)送get請求,直接調(diào)用`requests.get`就可以了。想要發(fā)送什么類型的請求,就調(diào)用什么方法。
?```python
response = requests.get("https://www.baidu.com/")
?```
## response的一些屬性:
?```python
import requests
kw = {'wd':'中國'}
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
# params 接收一個字典或者字符串的查詢參數(shù),字典類型自動轉換為url編碼,不需要urlencode()
response = requests.get("http://www.baidu.com/s", params = kw, headers = headers)
# 查看響應內(nèi)容,response.text 返回的是Unicode格式的數(shù)據(jù)
print(response.text)
# 查看響應內(nèi)容,response.content返回的字節(jié)流數(shù)據(jù)
print(response.content)
# 查看完整url地址
print(response.url)
# 查看響應頭部字符編碼
print(response.encoding)
# 查看響應碼
print(response.status_code)
?```
## response.text和response.content的區(qū)別:
1. response.content:這個是直接從網(wǎng)絡上面抓取的數(shù)據(jù)。沒有經(jīng)過任何解碼。所以是一個bytes類型。其實在硬盤上和在網(wǎng)絡上傳輸?shù)淖址际莃ytes類型。
2. response.text:這個是str的數(shù)據(jù)類型,是requests庫將response.content進行解碼的字符串。解碼需要指定一個編碼方式,requests會根據(jù)自己的猜測來判斷編碼的方式。所以有時候可能會猜測錯誤,就會導致解碼產(chǎn)生亂碼。這時候就應該使用`response.content.decode('utf-8')`進行手動解碼。
## 發(fā)送post請求:
發(fā)送post請求非常簡單。直接調(diào)用`requests.post`方法就可以了。
如果返回的是json數(shù)據(jù)。那么可以調(diào)用`response.json()`來將json字符串轉換為字典或者列表。
## 使用代理:
在請求方法中,傳遞`proxies`參數(shù)就可以了。
## 處理cookie:
如果想要在多次請求中共享cookie。那么應該使用session。示例代碼如下:
?```python
import requests
url = "http://www.renren.com/PLogin.do"
data = {"email":"970138074@qq.com",'password':"pythonspider"}
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
}
session = requests.Session()
session.post(url,data=data,headers=headers)
response = session.get('http://www.renren.com/880151247/profile')
with open('renren.html','w',encoding='utf-8') as fp:
fp.write(response.text)
?```
## 處理沒有授權的https協(xié)議:
數(shù)據(jù)解析
xpath庫
path語法
## 使用方式:
使用//獲取整個頁面當中的元素,然后寫標簽名,然后再寫謂詞進行提取。比如:
?```
//div[@class='abc']
?```
## 需要注意的知識點:
1. /和//的區(qū)別:/代表只獲取直接子節(jié)點。//獲取子孫節(jié)點。一般//用得比較多。當然也要視情況而定。
2. contains:有時候某個屬性中包含了多個值,那么可以使用`contains`函數(shù)。示例代碼如下:
```
//div[contains(@class,'job_detail')]
```
3. 謂詞中的下標是從1開始的,不是從0開始的。
## 使用lxml解析HTML代碼:
1. 解析html字符串:使用`lxml.etree.HTML`進行解析。示例代碼如下:
```python
htmlElement = etree.HTML(text)
print(etree.tostring(htmlElement,encoding='utf-8').decode("utf-8"))
```
2. 解析html文件:使用`lxml.etree.parse`進行解析。示例代碼如下:
```python
htmlElement = etree.parse("tencent.html")
print(etree.tostring(htmlElement, encoding='utf-8').decode('utf-8'))
```
這個函數(shù)默認使用的是`XML`解析器,所以如果碰到一些不規(guī)范的`HTML`代碼的時候就會解析錯誤,這時候就要自己創(chuàng)建`HTML`解析器。
```python
parser = etree.HTMLParser(encoding='utf-8')
htmlElement = etree.parse("lagou.html",parser=parser)
print(etree.tostring(htmlElement, encoding='utf-8').decode('utf-8'))
```
## lxml結合xpath注意事項:
1. 使用`xpath`語法。應該使用`Element.xpath`方法。來執(zhí)行xpath的選擇。示例代碼如下:
```python
trs = html.xpath("http://tr[position()>1]")
```
`xpath函數(shù)`返回來的永遠是一個列表。
2. 獲取某個標簽的屬性:
```python
href = html.xpath("http://a/@href")
# 獲取a標簽的href屬性對應的值
```
3. 獲取文本,是通過`xpath`中的`text()`函數(shù)。示例代碼如下:
```python
address = tr.xpath("./td[4]/text()")[0]
```
4. 指定獲取元素 下標范圍,是通過`xpath`中的`position()`函數(shù)。示例代碼如下:
```python
trs = html.xpath("http://tr[position()>1]")
```
5. 在某個標簽下,再執(zhí)行xpath函數(shù),獲取這個標簽下的子孫元素,那么應該在斜杠之前加一個點,代表是在當前元素下獲取。示例代碼如下:
```python
address = tr.xpath("./td[4]/text()")[0]
```
導入庫
from lxml import etree
解析 HTML文件 和文本
class ParseFile():
def parse_text(self):
text = """html文本"""
# 調(diào)用 HTML()方法 來加載 html文本,并結構化
htmlElement = etree.HTML(text)
print(etree.tostring(htmlElement,encoding='utf8').decode('utf-8') )
def parse_tencent_file(self):
# 調(diào)用 XML模塊中 etree類的parse方法,能導入文件并 解析
htmlElement = etree.parse("htmlElement.html")
print(etree.tostring(htmlElement, encoding='utf-8').decode('utf-8'))
def parse_lagou_file(self):
# 指定 HTMLParser解析器
# 調(diào)用 XML模塊中 etree類的parse方法,能導入文件并 解析
parser = etree.HTMLParser(encoding='utf8')
htmlElement = etree.parse('lagou.html',parser=parser)
print(etree.tostring(htmlElement,encoding='utf-8').decode('utf-8'))
使用xpath 提取 元素
class ExtractElement(object):
parser = etree.HTMLParser(encoding='utf8')
htmlElement = etree.parse("tencent.html", parser=parser)
# 1. 獲取所有tr標簽
# trs = htmlElement.xpath('//tr')
# for tr in trs:
# print(etree.tostring(tr,encoding='utf8').decode('utf-8'))
# 2. 獲取第2個tr標簽
# tr = htmlElement.xpath('//tr[2]')[0]
# print(etree.tostring(tr,encoding='utf-8').decode('utf-8'))
# 3. 獲取所有class等于even的tr標簽
# trs = htmlElement.xpath("http://tr[@class='even']")
# for tr in trs:
# print(etree.tostring(tr,encoding='utf-8').decode('utf-8'))
# 4. 獲取所有a標簽的href屬性
# aList = htmlElement.xpath("http://a/@href")
# for a in aList:
# print("http://hr.tencent.com/"+a)
# 5. 獲取所有的職位信息(純文本)
trs = htmlElement.xpath("http://tr[position()>1]") # position()方法 獲取 下標 大于 1 的 所有tr標簽
positions = []
for tr in trs:
# 在某個標簽下,再執(zhí)行xpath函數(shù),獲取這個標簽下的子孫元素
# 那么應該在//之前加一個點,代表是在當前元素下獲取
href = tr.xpath(".//a/@href")[0]
fullurl = 'http://hr.tencent.com/' + href
title = tr.xpath("./td[1]//text()")[0]
category = tr.xpath("./td[2]/text()")[0]
nums = tr.xpath("./td[3]/text()")[0]
address = tr.xpath("./td[4]/text()")[0]
pubtime = tr.xpath("./td[5]/text()")[0]
position = {
'url': fullurl,
'title': title,
'category': category,
'nums': nums,
'address': address,
'pubtime': pubtime
}
positions.append(position)
print(positions)
ExtractElement()
beautifulsoup庫
BeautifulSoup語法
## find_all的使用:
1. 在提取標簽的時候,第一個參數(shù)是標簽的名字。然后如果在提取標簽的時候想要使用標簽屬性進行過濾,
那么可以在這個方法中通過關鍵字參數(shù)的形式,將屬性的名字以及對應的值傳進去。或者是使用`attrs`屬性,
將所有的屬性以及對應的值放在一個字典中傳給`attrs`屬性。
2. 有些時候,在提取標簽的時候,不想提取那么多,那么可以使用`limit`參數(shù)。限制提取多少個。
## find與find_all的區(qū)別:
1. find:找到第一個滿足條件的標簽就返回。說白了,就是只會返回一個元素。
2. find_all:將所有滿足條件的標簽都返回。說白了,會返回很多標簽(以列表的形式)。
## 使用find和find_all的過濾條件:
1. 關鍵字參數(shù):將屬性的名字作為關鍵字參數(shù)的名字,以及屬性的值作為關鍵字參數(shù)的值進行過濾。
2. attrs參數(shù):將屬性條件放到一個字典中,傳給attrs參數(shù)。
## 獲取標簽的屬性:
1. 通過下標獲?。和ㄟ^標簽的下標的方式。
```python
href = a['href']
```
2. 通過attrs屬性獲?。菏纠a:
```python
href = a.attrs['href']
```
## string和strings、stripped_strings屬性以及get_text方法:
1. string:獲取某個標簽下的非標簽字符串。返回來的是個字符串。如果這個標簽下有多行字符,那么就不能獲取到了。
2. strings:獲取某個標簽下的子孫非標簽字符串。返回來的是個生成器。
2. stripped_strings:獲取某個標簽下的子孫非標簽字符串,會去掉空白字符。返回來的是個生成器。
4. get_text:獲取某個標簽下的子孫非標簽字符串。不是以列表的形式返回,是以普通字符串返回。
## CSS選擇器:
1. 根據(jù)標簽的名字選擇,示例代碼如下:
```css
p{
background-color: pink;
}
```
2. 根據(jù)類名選擇,那么要在類的前面加一個點。示例代碼如下:
```css
.line{
background-color: pink;
}
```
3. 根據(jù)id名字選擇,那么要在id的前面加一個#號。示例代碼如下:
```css
#box{
background-color: pink;
}
```
4. 查找子孫元素。那么要在子孫元素中間有一個空格。示例代碼如下:
```css
#box p{
background-color: pink;
}
```
5. 查找直接子元素。那么要在父子元素中間有一個>。示例代碼如下:
```css
#box > p{
background-color: pink;
}
```
6. 根據(jù)屬性的名字進行查找。那么應該先寫標簽名字,然后再在中括號中寫屬性的值。示例代碼如下:
```css
input[name='username']{
background-color: pink;
}
```
7. 在根據(jù)類名或者id進行查找的時候,如果還要根據(jù)標簽名進行過濾。那么可以在類的前面或者id的前面加上標簽名字。示例代碼如下:
```css
div#line{
background-color: pink;
}
div.line{
background-color: pink;
}
```
## BeautifulSop中使用css選擇器:
在`BeautifulSoup`中,要使用css選擇器,那么應該使用`soup.select()`方法。應該傳遞一個css選擇器的字符串給select方法。
## 常見的四種對象:
1. Tag:BeautifulSoup中所有的標簽都是Tag類型,并且BeautifulSoup的對象其實本質(zhì)上也是一個Tag類型。所以其實一些方法比如find、find_all并不是BeautifulSoup的,而是Tag的。
2. NavigableString:繼承自python中的str,用起來就跟使用python的str是一樣的。
3. BeautifulSoup:繼承自Tag。用來生成BeaufifulSoup樹的。對于一些查找方法,比如find、select這些,其實還是Tag的。
4. Comment:這個也沒什么好說,就是繼承自NavigableString。
## contents和children:
返回某個標簽下的直接子元素,其中也包括字符串。他們兩的區(qū)別是:contents返回來的是一個列表,children返回的是一個迭代器。
"""
導入庫
from bs4 import BeautifulSoup
bs4語法使用
from bs4 import BeautifulSoup
# html文本
html = """html文本"""
bs = BeautifulSoup(html,"lxml") # 創(chuàng)建一個bs4對象,傳入 html數(shù)據(jù),使用 lxml解析器來操作
## find_all()、string、stripped_strings 等方法 操作:
# 0. # 打印獲取的數(shù)據(jù)
# print(bs.prettify())
# tr = bs.find_all('tr')[1]
# text = tr.string
# print(text)
# 1. 獲取所有tr標簽
# trs = bs.find_all('tr')
# for tr in trs:
# print(tr)
# print('*'*30)
# 2. 獲取第2個tr標簽
# tr = bs.find_all('tr',limit=2)[1]
# print(tr)
# 3. 獲取所有class等于even的tr標簽
# trs = bs.find_all('tr',attrs={'class':"even"})
# for tr in trs:
# print(tr)
# print('='*30)
# 4. 將所有id等于test,class也等于test的a標簽提取出來。
# aList = bs.find_all('a',id='test',class_='test')
# aList2 = bs.find_all('a',attrs={'id':'test','class':'test'})
# for a in aList2:
# print(a)
# print('='*30)
# 5. 獲取所有a標簽的href屬性 ==> 通過操作字典對象方式, 取key鍵名 來獲取鍵值
# aList = bs.find_all('a')
# for a in aList:
# #1.通過下標操作方式
# href = a['href']
# print(href)
# print('*'*30)
#
# #2.通過attrs屬性方式
# href = a.attrs['href']
# print(href)
# 6. 獲取所有的職位信息(純文本)
# trs = bs.find_all('tr')[1:] # 切片:除第一個外,獲取所有tr元素
# movies = []
# for tr in trs:
# movie = {}
#
# ## 方式一: 通過 層級結構,獲取一個個相對應 數(shù)據(jù),再把數(shù)據(jù)組合添加到字典;最后把字典添加到列表;步驟繁多-操作復雜;
# # tds = tr.find_all("td")
# # title = tds[0].string
# # category = tds[1].string
# # nums = tds[2].string
# # city = tds[3].string
# # pubtime = tds[4].string
# # movie['title'] = title
# # movie['category'] = category
# # movie['nums'] = nums
# # movie['city'] = city
# # movie['pubtime'] = pubtime
# # movies.append(movie)
#
# ## 方式二: 去tags標簽、制表符、空格 信息,獲取 返回列表-文本數(shù)據(jù) ;通過下標取值; 操作簡單
# infos = list(tr.stripped_strings)
# print('infos:{}'.format(infos))
# movie['title'] = infos[0]
# movie['category'] = infos[1]
# movie['nums'] = infos[2]
# movie['city'] = infos[3]
# movie['pubtime'] = infos[4]
# movies.append(movie)
#
# print(movies)
CSS選擇器
## CSS選擇器: select()方法 操作
# 1. 獲取所有tr標簽
# trs = bs.select("tr")
# for tr in trs:
# print(type(tr))
# print('='*30)
# print(tr)
# break
# 2. 獲取第2個tr標簽
# tr = bs.select('tr')[1]
# print(tr)
# 3. 獲取所有class等于even的tr標簽
# # trs = bs.select(".even")
# trs2 = bs.select("tr[class='even']")
# for tr in trs2:
# print(tr)
# 4. 獲取所有a標簽的href屬性
# aList = bs.select('a')
# for a in aList:
# href = a['href']
# print(href)
# 5. 獲取所有的職位信息(純文本)
trs = bs.select('tr')
for tr in trs:
infos = list(tr.stripped_strings)
print(infos)
print('='*30)
print('職位名稱:',infos[0])
print('職位類別:',infos[1])
print('人數(shù):',infos[2])
print('地點:',infos[3])
print('發(fā)布時間:',infos[4])
re庫
導入庫
import re
re語法使用一:
import re
# 1.匹配某個字符串
# text = 'hello'
# rest = re.match('he',text)
# print(rest.group())
#2. .點,匹配任意字符
# text = "a\nd"
# ret = re.match('.',text)
# print(ret.group())
# 3. \d:匹配任意的數(shù)字( 0 - 9 )
# text = "+"
# text = "9+10"
# rest = re.match('\d',text)
# print(rest.group())
# 4. \D:匹配任意的非數(shù)字
# text = "a2"
# rest = re.match('\D',text)
# print(rest.group())
# 5. \s:匹配空白字符(\n,\t,\r,空格)
# text = "\r"
# rest = re.match('\s',text)
# print(rest.group())
# 6. \w:匹配 a-z,A-Z,數(shù)字和下劃線
# text = "adf"
# rest = re.match('\w',text)
# print(rest.group())
#7. \W 與 \w相反
# text = "|"
# rest = re.match('\W',text)
# print(rest.group())
# 8. []組合的方式,只要滿足中括號中的字符,就可以匹配
# text = "0731-88888888asfa"
# ret = re.match('[\d\-]+',text)
# print(ret.group())
# 8.1. 中括號的形式代替\d
# text = "09"
# ret = re.match('[0-9]',text)
# print(ret.group())
# 8.2. 中括號的形式代替\D
# text = "1"
# ret = re.match('[^0-9]',text)
# print(ret.group())
# 8.3. 中括號的形式代替\w
# text = "_"
# ret = re.match('[a-zA-Z0-9_]',text)
# print(ret.group())
# 8.4. 中括號的形式代替\W
# text = "0"
# ret = re.match('[^a-zA-Z0-9_]',text)
# print(ret.group())
匹配多個字符
# 9. *:可以匹配0或者任意多個字符
# text = "abcd"
# rest = re.match('\s*',text)
# print(rest.group())
# 10. +:匹配1個或者多個字符
# text = "+abcd"
# rest = re.match('\w+',text)
# print(rest.group())
# 11. ?:匹配一個或者0個 ( 1.沒有 2.只有一個)
# text = "abcd"
# rest = re.match('\w?',text)
# print(rest.group())
# 12.{m}:匹配m個字符
# text = 'abcd'
# rest = re.match('\w{2}',text)
# print(rest.group())
# 13. {m,n}:匹配 m - n 個字符
# text = 'abcd'
# rest = re.match('\w{2,5}',text)
# print(rest.group())
小案例
# 14.驗證手機號碼
# text = "12578900980"
# rest = re.match('1[34578]\d{9}',text)
# print(rest.group())
# 15. 驗證郵箱
# text = "2214866337@qq.com"
# rest = re.match('\w+@[a-z0-9]+\.[a-z]+',text)
# print(rest.group())
# 16. 驗證URL
# text = "https://baike.baidu.com/item/Python/407313?fr=aladdin"
# rest = re.match('(http|https|ftp)://[^\s]+',text) # ():匹配內(nèi)容 []:匹配范圍
# print(rest.group())
# 17. 驗證身份證:
# text = "31131118908123230X"
# ret = re.match('\d{17}[\dxX]',text)
# ret2 = re.match('\d{17}[\d|x|X]',text)
# print(ret.group(),ret2.group())
#
# 18. ^(脫字號),表示以...開頭:
# text = "hello"
# ret = re.search('^h',text)
# print(ret.group())
# 19. $:表示以...結尾:
# text = "xxx@163.com"
# ret = re.match('\w+@163.com$',text)
# print(ret.group())
# 20. |:匹配多個字符串或者表達式:
# text = "https"
# rest = re.match('(ftp|http|https)$',text)
# print(rest.group())
# 21:貪婪模式與非貪婪模式:
# text = "0123456"
# rest = re.match('\d+',text)
# print("貪婪模式= ",rest.group())
#
# text = "<h1>標題</h1>"
# ret = re.match('<.+?>',text)
# print("非貪婪模式= ",ret.group())
# 22:匹配0-100之間的數(shù)字
# # 可以出現(xiàn)的:1,2,3,10,100,99
# # 有三種情況:1,99,100
# # 不可以出現(xiàn)的:09,101
#
# text = '99'
# rest = re.match('[1-9]\d?$|100$',text)
# print(rest.group())
原聲字符 與 轉義字符
# import re
# # text = "apple price is $299" # 匹配 $299
# # ret = re.search("\$\d+",text) # $:在正則中有特殊意義,需轉義 \ => \$
# # print(ret.group())
#
# # r = raw = 原生的
# # text = '\n'
# # print(text)
#
#
# text = "\c" #= '\n'
# # python:'\\n' = \n
# # \\\\n =》 \\n
# # \\c
#
# # 正則表達式中:\n =
# # \\n =》 \n
# # \\c =》 \c
#
# rest = re.match(r'\\c',text)
# print(rest.group())
分組
import re
# text = "apple's price $99,orange's price is $10"
# ret = re.search('.*(\$\d+).*(\$\d+)',text)
# print('分組原字符串:',ret.group(0)) # ret.group(0) = ret.group()
# print('某個分組的值:',ret.group(1))
# print('某個分組的值:',ret.group(2))
# print("分組 = ",ret.group(1,2))
# print('所有的子分組都拿出來:',ret.groups())
find_all函數(shù)
text = "apple's price $99,orange's price is $10"
ret = re.findall('\$\d+',text) # 查找所有符合條件的值,放在列表中
print('findall()函數(shù): ',ret)
sub函數(shù)
# text = "apple's price $99,orange's price is $10"
# ret = re.sub('\$\d+',"0",text) # 把符合條件的值,替換
# print('sub()函數(shù): ',ret)
html = """
<dd class="job_bt">
<h3 class="description">職位描述:</h3>
<div>
<p>參與公司新一代面向生命科學行業(yè)云服務應用及平臺的開發(fā)。</p>
<p><br></p>
<p>【工作職責】</p>
<p>云服務軟件產(chǎn)品的架構設計與開發(fā)</p>
<p>與設計、產(chǎn)品及前端人員溝通,保證產(chǎn)品的質(zhì)量和開發(fā)進度</p>
<p>研究新興技術,對產(chǎn)品進行持續(xù)優(yōu)化</p>
<p><br></p>
<p>【職位要求】</p>
<p>計算機相關專業(yè)本科及以上學歷</p>
<p>對常見數(shù)據(jù)結構和面向?qū)ο笤O計有深入理解</p>
<p>熟練掌握Python語言,3年以上實際經(jīng)驗</p>
<p>熟悉Python Web開發(fā)框架如Django</p>
<p>熟練掌握數(shù)據(jù)庫開發(fā)和設計</p>
<p>基本的英文讀寫能力</p>
</div>
</dd>
"""
# ret = re.sub('<.+?>',"",html)
# print(ret)
split函數(shù)
# text = "hello&world ni hao"
# ret = re.split('[^a-zA-Z]',text)
# print('split分割函數(shù): ',ret)
compile()預編譯函數(shù)
# compile(): 預編譯函數(shù),用來寫 正則 ; 調(diào)用時 直接把對象傳入即可
# text = "the number is 20.50"
# # r = re.compile('\d+\.?\d*')
# r = re.compile(r"""
# \d+ # 小數(shù)點前面的數(shù)字
# \.? # 小數(shù)點本身
# \d* # 小數(shù)點后面的數(shù)字
# """,re.VERBOSE)
# ret = re.search(r,text)
# print(ret.group())
數(shù)據(jù)存儲
json庫
"""
在 Python 中。只有基本數(shù)據(jù)類型才能轉換成 JSON 格式的字符串:
即: int 、 float 、 str 、 list 、 dict 、 tuple 。
"""
字典和列表轉JSON
## 將Python對象轉換為 json字符串 ; 字典和列表轉JSON:
# import json
# books = [
# {
# 'title': '鋼鐵是怎樣練成的',
# 'price': 9.8
# },
# {
# 'title': '紅樓夢',
# 'price': 9.9
# }
# ]
# json_str = json.dumps(books,ensure_ascii=False)
# print(json_str)
寫入json文件
## 將json數(shù)據(jù)直接 dump 到文件中:
# import json
# books = [
# {
# 'title': '鋼鐵是怎樣練成的',
# 'price': 9.8
# },
# {
# 'title': '紅樓夢',
# 'price': 9.9
# }
# ]
# with open('books.json','w',encoding='utf-8') as fp:
# # 因為 json 在 dump 的時候,只能存放 ascii 的字符,因此會將中文進行轉義,這時候我們可以使用 ensure_ascii=False 關閉這個特性
# json.dump(books,fp,fp,ensure_ascii=False)
#
JSON轉字典和列表
## 將一個json字符串load成Python對象:
# import json
# json_str = '[{"title": "鋼鐵是怎樣練成的", "price": 9.8}, {"title": "紅樓夢", "price": 9.9}]'
# books = json.loads(json_str,encoding='utf-8')
# print(type(books))
# print(books)
讀取json文件
## 直接從文件中讀取json:
import json
with open('books.json','r',encoding='utf-8') as fp:
json_str = json.load(fp)
print(json_str)
csv庫
導入庫
import csv
讀取csv文件
############## 讀取csv文件:reader()、DictReader() ###############
import csv
## 讀取csv文件:
## 獲取數(shù)據(jù)的時候,就要通過下表來獲取數(shù)據(jù)
def read_csv_demo1():
with open('stock.csv', 'r') as fp:
# reader是一個迭代器
reader = csv.reader(fp)
# next(reader)
for x in reader:
name = x[3]
volumn = x[-1]
print({'name': name, 'volumn': volumn})
## 讀取csv文件:
## 可以使用 DictReader,在獲取數(shù)據(jù)的時候通過標題:
def read_csv_demo2():
with open('stock.csv','r') as fp:
# 使用DictReader創(chuàng)建的reader對象
# 不會包含標題那行的數(shù)據(jù)
# reader是一個迭代器,遍歷這個迭代器,返回來的是一個字典。
reader = csv.DictReader(fp)
for x in reader:
value = {"name":x['secShortName'],'volumn':x['turnoverVol']}
print(value)
寫入數(shù)據(jù)到csv文件
############## 寫入數(shù)據(jù)到csv文件::writerow()、DictWriter() ###############
import csv
## 寫入csv文件:
## writerow ,這個是寫入一行。一個是 writerows ,這個是寫入多行
def write_csv_demo1():
headers = ['username', 'age', 'height']
values = [
('張三', 18, 180),
('李四', 19, 190),
('王五', 20, 160)
]
with open('classroom.csv', 'w', encoding='utf-8', newline='') as fp:
writer = csv.writer(fp)
writer.writerow(headers)
writer.writerows(values)
## 寫入csv文件:
## 使用字典的方式把數(shù)據(jù)寫入進去。這時候就需要使用 DictWriter
def write_csv_demo2():
headers = ['username', 'age', 'height']
values = [
{'username':'張三','age':18,'height':180},
{'username':'李四','age':19,'height':190},
{'username':'王五','age':20,'height':160}
]
with open('classroo1.csv','w',encoding='utf-8',newline='') as fp:
writer = csv.DictWriter(fp,headers)
# 寫入表頭數(shù)據(jù)的時候,需要調(diào)用writeheader方法
writer.writeheader()
writer.writerows(values)
mysql庫
連接數(shù)據(jù)庫
import pymysql
database = {
'host':'127.0.0.1',
'port':3306,
'user':'python',
'password':'pythonvip',
'database':'spider_db'
}
"""
# cursor.execute(sql)
# 插入、刪除、更新。 都需要執(zhí)行commit操作 conn.commit() 提交執(zhí)行結果、conn.close()關閉連接
"""
# 連接數(shù)據(jù)庫
conn = pymysql.connect(**database)
# 獲取游標:擁有操作 mysql的 權限和方法
cursor = conn.cursor()
print(cursor)
增
# sql_insert_1 = "insert into spider_tb(name,sex,age) values('xiaoguo','女',26)" # 編寫 SQL語句
# sql_insert_1 = cursor.execute(sql_insert_1) # 執(zhí)行 SQL數(shù)據(jù)庫 語句
# conn.commit() # 提交執(zhí)行結果
# conn.close() # 關閉連接
刪
# sql_delete = 'delete from spider whwere id = {}'
# cursor.execute(sql_delete.format('1'))
# conn.commit()
# conn.close()
改
# sql_update = 'update spider set name={} where name={}'
# cursor.execute(sql_delete.sql_update('C#','Java'))
# conn.commit()
# conn.close()
查
######## all ########
# sql_select_all = "select * from spider"
# result = cursor.execute(sql_select_all)
# print(result)
# conn.close()
######## where ########
# sql_select_where = "select name,sex,age from spider where id=2"
# result = cursor.execute(sql_select_where)
# print(result)
# conn.close()
######## fetchone ########
# sql_select_fetchone = "select * from spider"
# cursor.execute(sql_select_fetchone)
# while True:
# result = cursor.fetchone()
# if result:
# print(result)
# else:
# break
#
# conn.close()
######## fetchall ########
# sql_select_fetchall = "select * from spider"
# cursor.execute(sql_select_fetchall)
# results = cursor.fetchall()
# for result in results:
# print(result)
# conn.close()
######## fetchmany ########
# sql_select_fetchmany = "select * from spider"
# cursor.execute(sql_select_fetchmany)
# results = cursor.fetchmany(3)
# for result in results:
# print(result)
# conn.close()
mongodb庫
連接
import pymongo
#獲取連接mongodb對象
client = pymongo.MongoClient("127.0.0.1",port= 27017)
連接數(shù)據(jù)庫與表
# 獲取數(shù)據(jù)庫[1.有則連接,2.無則-創(chuàng)建并連接]
db = client.study
# 獲取數(shù)據(jù)庫中的集合[理解為: MySQL中的表]
collection = db.table
增
# 1.單行寫入
# collection.insert({"username":'guokaichong'})
# 2.多行寫入
# collection.insert_many([
# {
# "username":"aaa",
# 'age': 18
# },
# {
# "username":"bbb",
# 'age': 20
# },
# {
# "username":"guokaichong",
# 'age': 20,
# 'job':'python工程師'
# },
# ])
刪
#1.單行刪除
# collection.delete_one({"username":"guokaichong"})
#2.多行刪除
# collection.delete_many({"username":"hackers"})
改
#1.單行修改
# collection.update_one({"username":'bbb'},{"$set":{"username":"hackers"}})
#.2多行修改
# collection.update_many({'username':'aaa'},{"$set":{"username":'hackers'}})
查
# 1.find方法:獲取集合中所以的數(shù)據(jù)
# cursor = collection.find()
# for x in cursor:
# print(x)
### 2.獲取集合中 一條數(shù)據(jù)
# result = collection.find_one({"age":20})
# print(result)
excel庫
讀取 Excel 文件
import xlrd
workbook = xlrd.open_workbook("成績表.xlsx")
sheet相關操作
"""
獲取 Sheet :
一個 Excel 中可能有多個 Sheet ,那么可以通過以下方法來獲取想要的 Sheet 信息:
1. sheet_names :獲取所有的 sheet 的名字。
2. sheet_by_index :根據(jù)索引獲取 sheet 對象。
3. sheet_by_name :根據(jù)名字獲取 sheet 對象。
4. sheets :獲取所有的 sheet 對象。
5. sheet.nrows :這個 sheet 中的行數(shù)。
6. sheet.ncols :這個 sheet 中的列數(shù)。
"""
##1.獲取所有sheet 表頭的名字
# sheets = workbook.sheet_names()
# print("獲取所以sheet 表頭的名字",sheets)
##2.根據(jù)索引獲取sheet
# for index in range(3):
# sheet = workbook.sheet_by_index(index)
# print(type(sheet))
# print(sheet.name)
##3.# 根據(jù)名稱獲取sheet
# sheet = workbook.sheet_by_name('1班')
# print(sheet.name)
##4.# 獲取所有的sheet對象
# for sheet in workbook.sheets():
# print(sheet.name)
##5.獲取這個sheet中的行數(shù)和列數(shù)
# sheet0 = workbook.sheet_by_index(0)
# print("行數(shù):%d"%sheet0.nrows)
# print('列數(shù):%d'%sheet0.ncols)
#
Cell相關操作
"""
獲取Cell及其屬性:
每個 Cell 代表的是表格中的一格。以下方法可以方便獲取想要的 cell :
1. sheet.cell(row,col) :獲取指定行和列的 cell 對象。
2. sheet.row_slice(row,start_col,end_col) :獲取指定行的某幾列的cell對象。
3. sheet.col_slice(col,start_row,end_row) :獲取指定列的某幾行的cell對象。
4. sheet.cell_value(row,col) :獲取指定行和列的值。
5. sheet.row_values(row,start_col,end_col) :獲取指定行的某幾列的值。
6. sheet.col_values(col,start_row,end_row) :獲取指定列的某幾行的值。
"""
sheet = workbook.sheet_by_index(0)
##使用cell方法獲取指定的cell對象
# cell = sheet.cell(0,0) # 第幾行,第幾列
# print(type(cell))
# print(cell)
##使用row_slice獲取第0行的1-2列的cell對象
# cells = sheet.row_slice(0,1,3) # 第幾行,第幾列,到第幾列
# total = sum([cell.value for cell in cells ])
# print(cells,total)
##使用col_slice獲取第0列的1-2行的cell對象
# cells = sheet.col_slice(0,1,3)
# print(cells)
# cells = sheet.col_slice(1,1,sheet.nrows)
# avg = sum([cell.value for cell in cells])/len(cells)
# print(cells,avg)
# scores = sheet.col_values(1,1,sheet.nrows)
# avg = sum(scores)/len(scores)
# print(avg)
Cell的數(shù)據(jù)類型
"""
Cell的數(shù)據(jù)類型:
1. xlrd.XL_CELL_TEXT(Text) :文本類型。
2. xlrd.XL_CELL_NUMBER(Number) :數(shù)值類型。
3. xlrd.XL_CELL_DATE(Date) :日期時間類型。
4. xlrd.XL_CELL_BOOLEAN(Bool) :布爾類型。
5. xlrd.XL_CELL_BLANK :空白數(shù)據(jù)類型。
"""
sheet = workbook.sheet_by_index(0)
# xlrd.XL_CELL_TEXT(Text) :文本類型。
# cell = sheet.cell(0,0)
# print(cell.ctype)
# print(xlrd.XL_CELL_TEXT)
# xlrd.XL_CELL_NUMBER(Number) :數(shù)值類型
# cell = sheet.cell(1,1)
# print(cell.ctype)
# print(xlrd.XL_CELL_NUMBER)
# xlrd.XL_CELL_DATE(Date) :日期時間類型
# cell = sheet.cell(19,0)
# print(cell.ctype)
# print(xlrd.XL_CELL_DATE)
# xlrd.XL_CELL_BOOLEAN(Bool)
# cell = sheet.cell(19,1)
# print(cell.ctype)
# print(xlrd.XL_CELL_BOOLEAN)
# xlrd.XL_CELL_BLANK :空白數(shù)據(jù)類型
# cell = sheet.cell(19,2)
# print(cell.ctype)
# print(xlrd.XL_CELL_EMPTY)
寫入Excel
寫入 Excel 步驟如下:
1. 導入 xlwt 模塊。
2. 創(chuàng)建一個 Workbook 對象。
3. 創(chuàng)建一個 Sheet 對象。
4. 使用 sheet.write(row,col,data) 方法把數(shù)據(jù)寫入到 Sheet 下指定行和列中。如果想要在原
來 workbook 對象上添加新的 cell ,那么需要調(diào)用 put_cell 來添加。
5. 保存成 Excel 文件。
"""
# import xlwt
# import random
# workbook = xlwt.Workbook(encoding='utf-8')
# sheet = workbook.add_sheet("成績表")
# # 添加表頭
# fields = ['數(shù)學','英語','語文']
# for index,field in enumerate(fields):
# sheet.write(0,index,field)
# # 隨機的添加成績
# for row in range(1,10):
# for col in range(3):
# grade = random.randint(0,100)
# sheet.write(row,col,grade)
# workbook.save("abc.xls")
編輯 Excel 文件
"""
編輯 Excel 文件:
如果想要在原來已經(jīng)存在的 Excel 文件中添加新的行或者新的列,那么需要采
用 put_cell(row,col,type,value,xf_index) 來添加進去,最后再放到 xlwt 創(chuàng)建的 workbook 中,
然后再保存進去
"""
import xlrd
import xlwt
workbook = xlrd.open_workbook("成績表.xlsx")
rsheet = workbook.sheet_by_index(0) # 從下標為 0 位置開始 讀取 sheet表
#
# # 添加 總分成績
# rsheet.put_cell(0,4,xlrd.XL_CELL_TEXT,"總分",None)
# for row in range(1,rsheet.nrows):
# grade = sum(rsheet.row_values(row,1,4))
# rsheet.put_cell(row,4,xlrd.XL_CELL_TEXT,grade,None)
#
# # 添加每個科目的平均分成績
# total_rows = rsheet.nrows
# total_cols = rsheet.ncols
# for col in range(1,total_cols):
# grades = rsheet.col_values(col,1,total_rows)
# avg_grade = sum(grades)/len(grades)
# print(type(avg_grade))
# rsheet.put_cell(total_rows,col,xlrd.XL_CELL_NUMBER,avg_grade,None)
#
# # 重新寫入一個 Excel 文件數(shù)據(jù)
# wwb = xlwt.Workbook(encoding='utf-8')
# wsheet = wwb.add_sheet("1班學生成績")
# for row in range(rsheet.ncols):
# for col in range(rsheet.ncols):
# wsheet.write(row,col,rsheet.cell_value(row,col))
#
# wwb.save("abc.xls")
案例
import xlrd
import xlwt
rwb = xlrd.open_workbook("成績表.xlsx")
rsheet = rwb.sheet_by_index(0)
# 添加總分的cell
rsheet.put_cell(0,4,xlrd.XL_CELL_TEXT,"總分",None)
# 添加總分的數(shù)據(jù)
nrows = rsheet.nrows
ncols = rsheet.ncols
for row in range(1,nrows):
scores = rsheet.row_values(row,1,4)
rsheet.put_cell(row,4,xlrd.XL_CELL_NUMBER,sum(scores),None)
# 添加每個科目的平均分
for col in range(1,rsheet.ncols):
scores = rsheet.col_values(col,1,nrows)
avg = sum(scores)/len(scores)
rsheet.put_cell(nrows,col,xlrd.XL_CELL_NUMBER,avg,None)
# 編輯的實質(zhì):讀取->編輯->寫入一個新的excel文件
wwb = xlwt.Workbook(encoding='utf-8')
wsheet = wwb.add_sheet("xxx")
for row in range(rsheet.nrows):
for col in range(rsheet.ncols):
value = rsheet.cell_value(row,col)
wsheet.write(row,col,value)
wwb.save("新成績表.xls")
進階
多線程
多線程介紹
"""
多線程介紹:
多線程是為了同步完成多項任務,通過提高資源使用效率來提高系統(tǒng)的效率。線程是在同一時間需
要完成多項任務的時候?qū)崿F(xiàn)的。
最簡單的比喻多線程就像火車的每一節(jié)車廂,而進程則是火車。車廂離開火車是無法跑動的,同理
火車也可以有多節(jié)車廂。多線程的出現(xiàn)就是為了提高效率。同時它的出現(xiàn)也帶來了一些問題。
threading 模塊是 python 中專門提供用來做多線程編程的模塊。threading 模塊中最常用的類是 Thread ;
使用 threading.enumerate() 函數(shù)便可以看到當前線程的數(shù)量。
"""
傳統(tǒng)的方式
# def coding():
# for x in range(3):
# print('正在寫代碼%s'%x)
# time.sleep(1)
#
# def drawing():
# for x in range(3):
# print('正在畫圖%s' % x)
# time.sleep(1)
#
#
# def main():
# coding()
# drawing()
#
# if __name__ == '__main__':
# main()
采用多線程的方式
# import time
# import threading
#
# def conding():
# for x in range(3):
# print('正在寫代碼%s'%threading.current_thread())
# time.sleep(1)
#
#
# def drawing():
# for x in range(3):
# print('正在畫圖%s' % threading.current_thread())
# time.sleep(1)
#
#
# def main():
# t1 = threading.Thread(target=conding)
# t2 = threading.Thread(target=drawing)
#
# t1.start()
# t2.start()
#
# print(threading.enumerate()) #使用 threading.enumerate() 函數(shù)便可以看到當前線程的數(shù)量。
#
#
# if __name__ == '__main__':
# main()
繼承自 threading.Thread 類
"""
繼承自 threading.Thread 類:
為了讓線程代碼更好的封裝。可以使用 threading 模塊下的 Thread 類,繼承自這個類,然后實
現(xiàn) run 方法,線程就會自動運行 run 方法中的代碼
"""
# import threading
# import time
#
# class CodinThread(threading.Thread):
# def run(self):
# for x in range(3):
# print('正在寫代碼%s'%threading.current_thread())
# time.sleep(1)
#
# class DrawingThread(threading.Thread):
# def run(self):
# print('正在畫圖%s' % threading.current_thread())
# time.sleep(1)
#
#
# def main():
# t1 = CodinThread()
# t2 = DrawingThread()
#
# t1.start()
# t2.start()
#
# if __name__ == '__main__':
# main()
多線程共享全局變量的問題
"""
多線程共享全局變量的問題:
多線程都是在同一個進程中運行的。因此在進程中的全局變量所有線程都是可共享的。這就造成了
一個問題,因為線程執(zhí)行的順序是無序的。有可能會造成數(shù)據(jù)錯誤:
結果 :因為多線程運行的不確定性。因此最后的結果可能是隨機的
"""
# import threading
#
# tickets = 0
# def get_ticket():
# global tickets
# for x in range(1000000):
# tickets += 1
# print('tickets:%d'%tickets)
#
# def main():
# for x in range(2):
# t = threading.Thread(target=get_ticket)
# t.start()
# if __name__ == '__main__':
# main()
鎖機制
"""
鎖機制:
為了解決以上使用共享全局變量的問題。 threading 提供了一個 Lock 類,這個類可以在某個線
程訪問某個變量的時候加鎖,其他線程此時就不能進來,直到當前線程處理完后,把鎖釋放了,其
他線程才能進來處理。
"""
# import threading
#
# VALUE = 0
# gLock = threading.Lock()
#
# def add_value():
# global VALUE
# gLock.acquire()
# for x in range(1000000):
# VALUE += 1
# gLock.release()
# print('value:%d'%VALUE)
# def main():
# for x in range(2):
# t = threading.Thread(target=add_value)
# t.start()
# if __name__ == '__main__':
# main()
Lock版本生產(chǎn)者和消費者模式
"""
Lock版本生產(chǎn)者和消費者模式:
生產(chǎn)者和消費者模式是多線程開發(fā)中經(jīng)常見到的一種模式。生產(chǎn)者的線程專門用來生產(chǎn)一些數(shù)據(jù),
然后存放到一個中間的變量中。消費者再從這個中間的變量中取出數(shù)據(jù)進行消費。但是因為要使用
中間變量,中間變量經(jīng)常是一些全局變量,因此需要使用鎖來保證數(shù)據(jù)完整性。以下是使
用 threading.Lock 鎖實現(xiàn)的“生產(chǎn)者與消費者模式”的一個例子:
# """
# import threading
# import random
# import time
#
# gMoney = 1000
# gLock = threading.Lock()
# gTimes = 0
#
# class Producer(threading.Thread):
# def run(self):
# global gMoney
# global gLock
# global gTimes
# while True:
# money = random.randint(100, 1000)
# gLock.acquire()
# if gTimes >= 10:
# gLock.release()
# break
# gMoney += money
# print('%s當前存入%s元錢,剩余%s元錢' % (threading.current_thread(), money, gMoney))
# gTimes += 1
# time.sleep(0.5)
# gLock.release()
#
# class Consumer(threading.Thread):
# def run(self):
# global gMoney
# global gLock
# global gTimes
# while True:
# money = random.randint(100, 500)
# gLock.acquire()
# if gMoney > money:
# gMoney -= money
# print('%s當前取出%s元錢,剩余%s元錢' % (threading.current_thread(), money, gMoney))
# time.sleep(0.5)
# else:
# if gTimes >= 10:
# gLock.release()
# break
# print("%s當前想取%s元錢,剩余%s元錢,不足!" % (threading.current_thread(),money,gMoney))
# gLock.release()
#
# def main():
# for x in range(5):
# Consumer(name='消費者線程%d'%x).start()
#
# for x in range(5):
# Producer(name='生產(chǎn)者線程%d'%x).start()
#
# if __name__ == '__main__':
# main()
Condition版的生產(chǎn)者與消費者模式
Condition版的生產(chǎn)者與消費者模式:
Lock 版本的生產(chǎn)者與消費者模式可以正常的運行。但是存在一個不足,在消費者中,總是通
過 while True 死循環(huán)并且上鎖的方式去判斷錢夠不夠。上鎖是一個很耗費CPU資源的行為。因此
這種方式不是最好的。還有一種更好的方式便是使用 threading.Condition 來實
現(xiàn)。 threading.Condition 可以在沒有數(shù)據(jù)的時候處于阻塞等待狀態(tài)。一旦有合適的數(shù)據(jù)了,還可
以使用 notify 相關的函數(shù)來通知其他處于等待狀態(tài)的線程。這樣就可以不用做一些無用的上鎖和
解鎖的操作??梢蕴岣叱绦虻男阅?。首先對 threading.Condition 相關的函數(shù)做個介
紹, threading.Condition 類似 threading.Lock ,可以在修改全局數(shù)據(jù)的時候進行上鎖,也可以
在修改完畢后進行解鎖。以下將一些常用的函數(shù)做個簡單的介紹:
1. acquire :上鎖。
2. release :解鎖。
3. wait :將當前線程處于等待狀態(tài),并且會釋放鎖??梢员黄渌€程使
用 notify 和 notify_all 函數(shù)喚醒。被喚醒后會繼續(xù)等待上鎖,上鎖后繼續(xù)執(zhí)行下面的代
碼。
4. notify :通知某個正在等待的線程,默認是第1個等待的線程。
5. notify_all :通知所有正在等待的線程。 notify 和 notify_all 不會釋放鎖。并且需要在 release 之前調(diào)用。
# import threading
# import random
# import time
#
# gMoney = 1000
# gCondition = threading.Condition()
# gTimes = 0
# gTotalTimes = 5
#
# class Producer(threading.Thread):
# def run(self):
# global gMoney
# global gCondition
# global gTimes
# while True:
# money = random.randint(100, 1000)
# gCondition.acquire()
# if gTimes >= gTotalTimes:
# gCondition.release()
# print('當前生產(chǎn)者總共生產(chǎn)了%s次'%gTimes)
# break
# gMoney += money
# print('%s當前存入%s元錢,剩余%s元錢' % (threading.current_thread(), money, gMoney))
# gTimes += 1
# time.sleep(0.5)
# gCondition.notify_all()
# gCondition.release()
#
# class Consumer(threading.Thread):
# def run(self):
# global gMoney
# global gCondition
# while True:
# money = random.randint(100, 500)
# gCondition.acquire()
# # 這里要給個while循環(huán)判斷,因為等輪到這個線程的時候
# # 條件有可能又不滿足了
# while gMoney < money:
# if gTimes >= gTotalTimes:
# gCondition.release()
# return
# print('%s準備取%s元錢,剩余%s元錢,不足!'%(threading.current_thread(),money,gMoney))
# gCondition.wait()
# gMoney -= money
# print('%s當前取出%s元錢,剩余%s元錢' % (threading.current_thread(), money, gMoney))
# time.sleep(0.5)
# gCondition.release()
#
# def main():
# for x in range(5):
# Consumer(name='消費者線程%d'%x).start()
#
# for x in range(2):
# Producer(name='生產(chǎn)者線程%d'%x).start()
#
# if __name__ == '__main__':
# main()
Queue線程安全隊列
"""
Queue線程安全隊列:
在線程中,訪問一些全局變量,加鎖是一個經(jīng)常的過程。如果你是想把一些數(shù)據(jù)存儲到某個隊列
中,那么Python內(nèi)置了一個線程安全的模塊叫做 queue 模塊。Python中的queue模塊中提供了同
步的、線程安全的隊列類,包括FIFO(先進先出)隊列Queue,LIFO(后入先出)隊列
LifoQueue。這些隊列都實現(xiàn)了鎖原語(可以理解為原子操作,即要么不做,要么都做完),能夠
在多線程中直接使用??梢允褂藐犃衼韺崿F(xiàn)線程間的同步。相關的函數(shù)如下:
1. 初始化Queue(maxsize):創(chuàng)建一個先進先出的隊列。
2. qsize():返回隊列的大小。
3. empty():判斷隊列是否為空。
4. full():判斷隊列是否滿了。
5. get():從隊列中取最后一個數(shù)據(jù)。
6. put():將一個數(shù)據(jù)放到隊列中。
"""
from queue import Queue
import time
import threading
# q = Queue(4)
# for x in range(4):
# print( q.put(x))
#
# for x in range(4):
# print(q.get())
### 小案例;
# def set_value(q):
# index = 0
# while True:
# q.put(index)
# index += 1
# time.sleep(3)
#
# def get_value(q):
# while True:
# print(q.get())
#
# def main():
# q = Queue(4)
# t1 = threading.Thread(target=set_value,args=[q])
# t2 = threading.Thread(target=get_value,args=[q])
#
# t1.start()
# t2.start()
#
#
# if __name__ == '__main__':
# main()
selenium自動化
介紹與應用
"""
動態(tài)網(wǎng)頁數(shù)據(jù)抓取
什么是AJAX:
AJAX(Asynchronouse JavaScript And XML)異步JavaScript和XML。過在后臺與服務器進行少
量數(shù)據(jù)交換,Ajax 可以使網(wǎng)頁實現(xiàn)異步更新。這意味著可以在不重新加載整個網(wǎng)頁的情況下,對
網(wǎng)頁的某部分進行更新。傳統(tǒng)的網(wǎng)頁(不使用Ajax)如果需要更新內(nèi)容,必須重載整個網(wǎng)頁頁面。
因為傳統(tǒng)的在傳輸數(shù)據(jù)格式方面,使用的是 XML 語法。因此叫做 AJAX ,其實現(xiàn)在數(shù)據(jù)交互基本
上都是使用 JSON 。使用AJAX加載的數(shù)據(jù),即使使用了JS,將數(shù)據(jù)渲染到了瀏覽器中,在 右鍵->
查看網(wǎng)頁源代碼 還是不能看到通過ajax加載的數(shù)據(jù),只能看到使用這個url加載的html代碼。
獲取ajax數(shù)據(jù)的方式:
1. 直接分析ajax調(diào)用的接口。然后通過代碼請求這個接口。
2. 使用Selenium+chromedriver模擬瀏覽器行為獲取數(shù)據(jù)。
"""
"""
Selenium+chromedriver獲取動態(tài)數(shù)據(jù):
Selenium 相當于是一個機器人??梢阅M人類在瀏覽器上的一些行為,自動處理瀏覽器上的一些
行為,比如點擊,填充數(shù)據(jù),刪除cookie等。 chromedriver 是一個驅(qū)動 Chrome 瀏覽器的驅(qū)動程
序,使用他才可以驅(qū)動瀏覽器。當然針對不同的瀏覽器有不同的driver。以下列出了不同瀏覽器及
其對應的driver
"""
快速入門
"""
快速入門:
現(xiàn)在以一個簡單的獲取百度首頁的例子來講下 Selenium 和 chromedriver 如何快速入門:
"""
# import os
# from selenium import webdriver
#
#
# # chromedriver的絕對路徑
# driver_path = os.path.abspath('phantomjs.exe') # chrome.exe
# # 初始化一個driver,并指定chromedriver的路徑
# driver = webdriver.PhantomJS(executable_path=driver_path)
# # 請求網(wǎng)頁
# driver.get('https://www.baidu.com')
# # 通過page_source 獲取網(wǎng)頁源代碼
# print(driver.page_source)
selenium常用操作
"""
selenium常用操作:
關閉頁面:
1. driver.close() :關閉當前頁面。
2. driver.quit() :退出整個瀏覽器。
"""
# from selenium import webdriver
# import time
#
# webdriver = webdriver.PhantomJS()
# webdriver.get('https://www.baidu.com/')
# time.sleep(5)
# webdriver.quit()
定位元素
find_element_by_id :根據(jù)id來查找某個元素。等價于:
submitTag = driver.find_element_by_id('su')
submitTag1 = driver.find_element(By.ID,'su')
find_element_by_class_name :根據(jù)類名查找元素。 等價于:
submitTag = driver.find_element_by_class_name('su')
submitTag1 = driver.find_element(By.CLASS_NAME,'su')
find_element_by_name :根據(jù)name屬性的值來查找元素。等價于:
submitTag = driver.find_element_by_name('email')
submitTag1 = driver.find_element(By.NAME,'email')
find_element_by_tag_name :根據(jù)標簽名來查找元素。等價于:
submitTag = driver.find_element_by_tag_name('div')
submitTag1 = driver.find_element(By.TAG_NAME,'div')
find_element_by_xpath :根據(jù)xpath語法來獲取元素。等價于:
submitTag = driver.find_element_by_xpath('//div')
submitTag1 = driver.find_element(By.XPATH,'//div')
find_element_by_css_selector :根據(jù)css選擇器選擇元素。等價于:
submitTag = driver.find_element_by_css_selector('//div')
submitTag1 = driver.find_element(By.CSS_SELECTOR,'//div')
# 要注意,find_element 是獲取第一個滿足條件的元素。find_elements 是獲取所有滿足條件的元素。
# 1. 如果只是想要解析網(wǎng)頁中的數(shù)據(jù),那么推薦將網(wǎng)頁源代碼扔給lxml來解析。因為lxml底層使用的是C語言,所以解析效率會更高。
# 2. 如果是想要對元素進行一些操作,比如給一個文本框輸入值,或者是點擊某個按鈕,那么就必須使用selenium給我們提供的查找元素的方法。
"""
# from selenium import webdriver
# from lxml import etree
# from selenium.webdriver.common.by import By
#
# driver_path = r"C:\Users\Administrator\AppData\Local\Google\Chrome\Application\chrome.exe"
# driver = webdriver.PhantomJS(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# # html = etree.HTML(driver.page_source)
# # html.xpath("")
#
# # inputTag = driver.find_element_by_id('kw')
# # inputTag = driver.find_element_by_name('wd')
# inputTag = driver.find_elements(By.CSS_SELECTOR,".quickdelete-wrap > input")[0]
# print(inputTag)
# inputTag.send_keys('python')
操作表單元素
"""
操作表單元素:
1. 操作輸入框:分為兩步。第一步:找到這個元素。第二步:使用 send_keys(value) ,將數(shù)據(jù)填充進去
2. 操作checkbox:因為要選中 checkbox 標簽,在網(wǎng)頁中是通過鼠標點擊的。因此想要選
中 checkbox 標簽,那么先選中這個標簽,然后執(zhí)行 click 事件。
3. 選擇select:select元素不能直接點擊。因為點擊后還需要選中元素。這時候selenium就專門
為select標簽提供了一個類 selenium.webdriver.support.ui.Select 。將獲取到的元素當成參
數(shù)傳到這個類中,創(chuàng)建這個對象。以后就可以使用這個對象進行選擇了。
4. 操作按鈕:操作按鈕有很多種方式。比如單擊、右擊、雙擊等。這里講一個最常用的。就是點擊。直接調(diào)用 click 函數(shù)就可以了
# 常見的表單元素:
input type='text/password/email/number'
# buttton、input[type='submit']
# checkbox:input='checkbox'
# select:下拉列表
"""
操作輸入框
### 操作輸入框
# from selenium import webdriver
# import time
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# inputTag = driver.find_element_by_id('kw')
# inputTag.send_keys('python')
#
# time.sleep(3)
#
# inputTag.clear()
操作checkbox
### 操作checkbox
# from selenium import webdriver
# import time
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.douban.com/')
#
# rememberBtn = driver.find_element_by_name('remember')
# rememberBtn.click()
操作 select標簽
### 操作 select標簽
# from selenium import webdriver
# from selenium.webdriver.support.ui import Select
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('http://www.dobai.cn/')
#
# selectBtn = Select(driver.find_element_by_name('jumpMenu'))
# # selectBtn.select_by_index(1)
# # selectBtn.select_by_value("http://m.95xiu.com/")
# selectBtn.select_by_visible_text("95秀客戶端")
案例: 輸入-信息,點擊搜索
# from selenium import webdriver
# from selenium.webdriver.support.ui import Select
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# inputTag = driver.find_element_by_id('kw')
# inputTag.send_keys('python')
#
# submitTag = driver.find_element_by_id('su')
# submitTag.click()
行為鏈
"""
行為鏈:
有時候在頁面中的操作可能要有很多步,那么這時候可以使用鼠標行為鏈類 ActionChains 來完
成。比如現(xiàn)在要將鼠標移動到某個元素上并執(zhí)行點擊事件。
還有更多的鼠標相關的操作。
click_and_hold(element):點擊但不松開鼠標。
context_click(element):右鍵點擊。
double_click(element):雙擊。 更多方法請參考:http://selenium?python.readthedocs.io/api.html
"""
# from selenium import webdriver
# from selenium.webdriver.common.action_chains import ActionChains
# import time
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.PhantomJS(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# inputTag = driver.find_element_by_id('kw')
# submitBtn = driver.find_element_by_id('su')
#
# actions = ActionChains(driver)
# actions.move_to_element(inputTag)
# actions.send_keys_to_element(inputTag,'python')
# actions.move_to_element(submitBtn)
# actions.click(submitBtn)
# actions.perform() # 執(zhí)行-代碼
Cookie操作
"""
Cookie操作:
1. 獲取所有的 cookie :
for cookie in driver.get_cookies():
print(cookie)
2. 根據(jù)cookie的key獲取value:
value = driver.get_cookie(key)
3. 刪除所有的cookie:
driver.delete_all_cookies()
4. 刪除某個 cookie :
driver.delete_cookie(key)
"""
# from selenium import webdriver
# from selenium.webdriver.common.action_chains import ActionChains
# import time
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# for cookie in driver.get_cookies():
# print(cookie)
#
# print('='*30)
#
# print(driver.get_cookie("PSTM"))
#
# driver.delete_cookie("PSTM")
# print('='*30)
# # print(driver.get_cookie('PSTM'))
# driver.delete_all_cookies()
頁面等待
"""
頁面等待:
現(xiàn)在的網(wǎng)頁越來越多采用了 Ajax 技術,這樣程序便不能確定何時某個元素完全加載出來了。如果
實際頁面等待時間過長導致某個dom元素還沒出來,但是你的代碼直接使用了這個WebElement,
那么就會拋出NullPointer的異常。為了解決這個問題。所以 Selenium 提供了兩種等待方式:一種
是隱式等待、一種是顯式等待。
隱式等待: driver.implicitly_wait(time)、
顯式等待:WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "myDynamicElement")))
一些其他的等待條件:presence_of_element_located:某個元素已經(jīng)加載完畢了。
presence_of_all_emement_located:網(wǎng)頁中所有滿足條件的元素都加載完畢了。
element_to_be_cliable:某個元素是可以點擊了。
"""
# from selenium import webdriver
# from selenium.webdriver.support.ui import WebDriverWait
# from selenium.webdriver.support import expected_conditions as EC
# from selenium.webdriver.common.by import By
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.douban.com/')
#
# ## 隱式等待:調(diào)用 driver.implicitly_wait 。那么在獲取不可用的元素之前,會先等待10秒中的時間。
# # driver.implicitly_wait(20)
#
# """
# 顯示等待:顯示等待是表明某個條件成立后才執(zhí)行獲取元素的操作。也可以在等待的時候指定
# 一個最大的時間,如果超過這個時間那么就拋出一個異常。顯示等待應該使
# 用 selenium.webdriver.support.excepted_conditions 期望的條件
# 和 selenium.webdriver.support.ui.WebDriverWait 來配合完成
# """
# element = WebDriverWait(driver,10).until(
# EC.presence_of_element_located((By.ID,'form_email'))
# )
# print(element)
切換頁面
"""
切換頁面:
有時候窗口中有很多子tab頁面。這時候肯定是需要進行切換的。 selenium 提供了一個叫
做 switch_to_window 來進行切換,具體切換到哪個頁面,可以從 driver.window_handles 中找到
# 雖然在窗口中切換到了新的頁面。但是driver中還沒有切換。
# 如果想要在代碼中切換到新的頁面,并且做一些爬蟲。
# 那么應該使用driver.switch_to_window來切換到指定的窗口
# 從driver.window_handlers中取出具體第幾個窗口
# driver.window_handlers是一個列表,里面裝的都是窗口句柄。
# 他會按照打開頁面的順序來存儲窗口的句柄。
"""
# from selenium import webdriver
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# # driver.get("https://www.douban.com/")
# driver.execute_script("window.open('https://www.douban.com/')")
# print(driver.window_handles)
# driver.switch_to_window(driver.window_handles[1])
#
# print(driver.current_url)
# print(driver.page_source)
設置代理ip
"""
設置代理ip:
有時候頻繁爬取一些網(wǎng)頁。服務器發(fā)現(xiàn)你是爬蟲后會封掉你的ip地址。這時候我們可以更改代理
ip。更改代理ip,不同的瀏覽器有不同的實現(xiàn)方式。
"""
# from selenium import webdriver
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# options = webdriver.ChromeOptions()
# options.add_argument("--proxy-server=http://60.17.239.207:31032")
#
# driver = webdriver.Chrome(executable_path=driver_path,chrome_options=options)
#
# driver.get("http://httpbin.org/ip")
WebElement 元素
"""
WebElement 元素:
from selenium.webdriver.remote.webelement import WebElement 類是每個獲取出來的元素的所屬
類。
有一些常用的屬性:
1. get_attribute:這個標簽的某個屬性的值。
2. screentshot:獲取當前頁面的截圖。這個方法只能在 driver 上使用。
driver 的對象類,也是繼承自 WebElement
"""
from selenium import webdriver
from selenium.webdriver.remote.webelement import WebElement
driver = webdriver.PhantomJS()
driver.get('https://www.baidu.com/')
submitBtn = driver.find_element_by_id('su')
print(type(submitBtn))
print(submitBtn.get_attribute("value"))
driver.save_screenshot('baidu.png')