requests
- requests模塊:是對urllib的封裝,可以實現(xiàn)urllib的所有功能
- 并且api調(diào)用更加簡單方便
url, :要請求的目標(biāo)url
params:get請求后面要拼接的參數(shù)
:param method: 要發(fā)起的是什么類型的請求.
:param url: 要請求的目標(biāo)url
:param params: get請求后面要拼接的參數(shù)
:param data: Dictionary, post請求的表單數(shù)據(jù)
:param json: 傳遞json數(shù)據(jù)跟上面的data效果類似
:param headers: (optional) Dictionary 請求頭
:param cookies: (optional) Dict or CookieJar object (設(shè)置cookies信息模擬用戶請求)
:param files: 上傳文件
:param auth: 網(wǎng)站需要驗證的信息(賬號和密碼)
:param timeout: 設(shè)置請求的超時時間
:param allow_redirects: bool,是否允許重定向
:param proxies: (optional) Dictionary (設(shè)置代理)
:param verify: Defaults toTrue
.(忽略證書認(rèn)證,默認(rèn)為True表示不忽略)
- requests.session():維持會話,可以讓我們在跨請求時保存某些參數(shù)
xpath
xpath:可以在xml中查找信息,對xml文檔中元素進行遍歷和屬性的提取
xml:被設(shè)計的目的是為了傳輸數(shù)據(jù),結(jié)構(gòu)和html非常相識,是一種標(biāo)記語言
xpath常見的語法:
nodename 選取此節(jié)點的所有子節(jié)點
/ 從根節(jié)點開始查找
// 匹配節(jié)點,不考慮節(jié)點的位置
. 選取當(dāng)前節(jié)點
.. 選取當(dāng)前節(jié)點的父節(jié)點
a/@href 取標(biāo)簽的數(shù)據(jù)
a/text() 取標(biāo)簽的文本
a[@class="123"] 根據(jù)class屬性尋找標(biāo)簽
a[@id="123"] 根據(jù)id屬性尋找標(biāo)簽
a[@id="123"][last()] 取最后一個id為123的a標(biāo)簽
a[@id="123"][postion() < 2] 取id為123的前兩個a標(biāo)簽
pyquery
語法規(guī)則類似于Jquery,可以對html文本進行解析
q = PyQuery(html文檔)
pq('css選擇器')
items():獲取到多個標(biāo)簽時,使用items()將PyQuery轉(zhuǎn)換為一個生成器
然后在使用for in 循環(huán)
filter('css選擇器'):過濾
text():獲取標(biāo)簽的文本
attr('屬性名')獲取屬性值
beautifulsoup
作用是從html/xml中提取數(shù)據(jù),會載入整個HTML DOM,比lxml解析器效率要低
re
. :表示匹配除了換行符之外的任意字符
\ :轉(zhuǎn)義字符
[a-z] : 匹配a-z里面的任意一個字符
\d: 匹配數(shù)字 -> [0-9]
\D: 匹配非數(shù)字 [^\d]
\s: 匹配空白字符(空格,\n,\t...)
\S: 匹配非空白字符
\w: 匹配單詞字符 [A-Za-z0-9_]
\W: 匹配非單子字符
^:匹配以...開頭
$:匹配以....結(jié)尾
():分組
|:或
- 多字符匹配
*:匹配*前面的字符任意次數(shù)
+: 匹配+號前面的字符至少1次
?: 匹配?前面的字符0次或1次
{m}:匹配{m}前面的字符m次
{m,n}:匹配{m,n}前面的字符m~n次
- 非貪婪匹配
*?
+?
??
{m,n}?
match 方法:從起始位置開始查找,一次匹配
search 方法:從任何位置開始查找,一次匹配
findall 方法:全部匹配,返回列表
finditer 方法:全部匹配,返回迭代器
split 方法:分割字符串,返回列表
sub 方法:替換
多線程
- threading.Thread參數(shù)介紹
target:線程執(zhí)行的函數(shù)
name:線程名稱
args:執(zhí)行函數(shù)中需要傳遞的參數(shù),元組類型 另外:注意daemon參數(shù)
如果某個子線程的daemon屬性為False,主線程結(jié)束時會檢測該子線程是否結(jié)束,如果該子線程還在運行,則主線程會等待它完成后再退出;
如果某個子線程的daemon屬性為True,主線程運行結(jié)束時不對這個子線程進行檢查而直接退出,同時所有daemon值為True的子線程將隨主線程一起結(jié)束,而不論是否運行完成。
屬性daemon的值默認(rèn)為False,如果需要修改,必須在調(diào)用start()方法啟動線程之前進行設(shè)置
互斥鎖
當(dāng)多個線程幾乎同時修改某一個共享數(shù)據(jù)的時候,需要進行同步控制
線程同步能夠保證多個線程安全訪問競爭資源,最簡單的同步機制是引入互斥鎖。
互斥鎖為資源引入一個狀態(tài):鎖定/非鎖定
某個線程要更改共享數(shù)據(jù)時,先將其鎖定,此時資源的狀態(tài)為“鎖定”,其他線程不能更改;直到該線程釋放資源,將資源的狀態(tài)變成“非鎖定”,其他的線程才能再次鎖定該資源。互斥鎖保證了每次只有一個線程進行寫入操作,從而保證了多線程情況下數(shù)據(jù)的正確性。
threading模塊中定義了Lock類,可以方便的處理鎖定:
創(chuàng)建鎖
mutex = threading.Lock()
鎖定
mutex.acquire()
釋放
mutex.release()
鎖的好處:
確保了某段關(guān)鍵代碼只能由一個線程從頭到尾完整地執(zhí)行
鎖的壞處:
阻止了多線程并發(fā)執(zhí)行,包含鎖的某段代碼實際上只能以單線程模式執(zhí)行,效率就大大地下降了
由于可以存在多個鎖,不同的線程持有不同的鎖,并試圖獲取對方持有的鎖時,可能會造成死鎖
死鎖問題
在線程間共享多個資源的時候,如果兩個線程分別占有一部分資源并且同時等待對方的資源,就會造成死鎖。
盡管死鎖很少發(fā)生,但一旦發(fā)生就會造成應(yīng)用的停止響應(yīng)
多進程
進程:一個程序運行起來后,代碼+用到的資源 稱之為進程,它是操作系統(tǒng)分配資源的基本單元。
不僅可以通過線程完成多任務(wù),進程也是可以的
multiprocessing模塊就是跨平臺版本的多進程模塊,提供了一個Process類來代表一個進程對象,這個對象可以理解為是一個獨立的進程,可以執(zhí)行另外的事情
Queue的使用
Queue本身是一個消息列隊程序
Queue.qsize():返回當(dāng)前隊列包含的消息數(shù)量;
Queue.empty():如果隊列為空,返回True,反之False ;
Queue.full():如果隊列滿了,返回True,反之False;
Queue.get(block, timeout):獲取隊列中的一條消息,然后將其從列隊中移除,block默認(rèn)值為True;
1)如果block使用默認(rèn)值,且沒有設(shè)置timeout(單位秒),消息列隊如果為空,此時程序?qū)⒈蛔枞ㄍT谧x取狀態(tài)),直到從消息列隊讀到消息為止,如果設(shè)置了timeout,則會等待timeout秒,若還沒讀取到任何消息,則拋出"Queue.Empty"異常;
2)如果block值為False,消息列隊如果為空,則會立刻拋出"Queue.Empty"異常;
Queue.get_nowait():相當(dāng)Queue.get(False);
Queue.put(item,block,timeout):將item消息寫入隊列,block默認(rèn)值為True;
1)如果block使用默認(rèn)值,且沒有設(shè)置timeout(單位秒),消息列隊如果已經(jīng)沒有空間可寫入,此時程序?qū)⒈蛔枞ㄍT趯懭霠顟B(tài)),直到從消息列隊騰出空間為止,如果設(shè)置了timeout,則會等待timeout秒,若還沒空間,則拋出"Queue.Full"異常;
2)如果block值為False,消息列隊如果沒有空間可寫入,則會立刻拋出"Queue.Full"異常;
Queue.put_nowait(item):相當(dāng)Queue.put(item, False);
- Queue實例以及在多進程間的使用
multiprocessing.Pool常用函數(shù)解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式調(diào)用func(并行執(zhí)行,堵塞方式必須等待上一個進程退出才能執(zhí)行下一個進程),args為傳遞給func的參數(shù)列表,kwds為傳遞給func的關(guān)鍵字參數(shù)列表;
close():關(guān)閉Pool,使其不再接受新的任務(wù);
terminate():不管任務(wù)是否完成,立即終止;
join():主進程阻塞,等待子進程的退出, 必須在close或terminate之后使用;
進程與線程的對比
進程、線程對比 功能
進程,能夠完成多任務(wù),比如 在一臺電腦上能夠同時運行多個QQ
線程,能夠完成多任務(wù),比如 一個QQ中的多個聊天窗口
定義的不同
進程是系統(tǒng)進行資源分配基本單位.
線程是進程的一個實體,是CPU調(diào)度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.
線程自己基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(如程序計數(shù)器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享所在進程所擁有的全部資源
區(qū)別
一個程序至少有一個進程,一個進程至少有一個線程.
線程的劃分尺度小于進程(資源比進程少),使得多線程程序的并發(fā)性高。
進程在執(zhí)行過程中擁有獨立的內(nèi)存單元,而多個線程共享內(nèi)存,從而極大地提高了程序的運行效率
線線程不能夠獨立執(zhí)行,必須依存在進程中
優(yōu)缺點
線程和進程在使用上各有優(yōu)缺點:線程執(zhí)行開銷小,但不利于資源的管理和保護;而進程正相反。
使用場景:
多進程常用來處理計算密集型任務(wù): 計算密集型任務(wù)的特點:是要進行大量的計算,消耗CPU資源,比如計算圓周率、對視頻進行高清解碼等等,全靠CPU的運算能力。計算密集型任務(wù)可以用多任務(wù)完成,但是任務(wù)越多,花在任務(wù)切換的時間就越多,CPU執(zhí)行任務(wù)的效率就越低,所以,要最高效地利用CPU,計算密集型任務(wù)同時進行的數(shù)量應(yīng)當(dāng)?shù)扔贑PU的核心數(shù)。
多線程常用來處理IO密集型任務(wù): IO密集型:涉及到網(wǎng)絡(luò)、磁盤IO的任務(wù)都是IO密集型任務(wù),特點是CPU消耗很少,任務(wù)的大部分時間都在等待IO操作完成(因為IO的速度遠遠低于CPU和內(nèi)存的速度)。但是也要切記,在執(zhí)行多任務(wù)時,并不是越多線程越好。
SELENIUM
Selenium是一個Web的自動化測試工具,最初是為網(wǎng)站自動化測試而開發(fā)的,類型像我們玩游戲用的按鍵精靈,可以按指定的命令自動操作,不同是Selenium 可以直接運行在瀏覽器上,它支持所有主流的瀏覽器(包括PhantomJS這些無界面的瀏覽器)。 Selenium 可以根據(jù)我們的指令,讓瀏覽器自動加載頁面,獲取需要的數(shù)據(jù),甚至頁面截屏,或者判斷網(wǎng)站上某些動作是否發(fā)生。
Selenium 自己不帶瀏覽器,不支持瀏覽器的功能,它需要與第三方瀏覽器結(jié)合在一起才能使用。但是我們有時候需要讓它內(nèi)嵌在代碼中運行,所以我們可以用一個叫 PhantomJS 的工具代替真實的瀏覽器。
主要使用的方法和代碼如下
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException,TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
# 要想調(diào)用鍵盤按鍵操作需要引入keys包
from selenium.webdriver.common.keys import Keys
# 加載網(wǎng)頁(使用火狐瀏覽器加載)
# driver = webdriver.Firefox(executable_path='/home/ljh/桌面/driver/geckodriver')
# driver.get('https://www.baidu.com/')
# 加載網(wǎng)頁(使用無頭瀏覽器加載)
# driver = webdriver.PhantomJS(executable_path='/home/ljh/桌面/driver/phantomjs')
# driver.get('https://www.baidu.com/')
# 加載網(wǎng)頁(使用谷歌瀏覽器加載)
# 創(chuàng)建chrome參數(shù)對象
# opt = webdriver.ChromeOptions()
# 把chrome設(shè)置成為無界面模式
# opt.set_headless()
# driver = webdriver.Chrome(
options=opt, executable_path='/Users/ljh/Desktop/chromedriver'
)
driver = webdriver.Chrome(executable_path='/home/ljh/桌面/driver/chromedriver')
#設(shè)置頁面的加載超時時間
driver.set_page_load_timeout(0.1)
#處理異常
try:
driver.get('https://www.baidu.com/')
driver.save_screenshot('prcture.png')
except TimeoutException as err:
print(err)
#定位和操作
# driver.find_element_by_xpath():根據(jù)xpath定位節(jié)點
# driver.find_element_by_class_name():根據(jù)類名定位節(jié)點
# driver.find_element_by_partial_link_text():根據(jù)部分文本內(nèi)容定位節(jié)點
# driver.find_element_by_css_selector():根據(jù)css選擇器定位節(jié)點
# driver.find_element_by_link_text():根據(jù)完整文本定位節(jié)點
driver.find_element_by_id('kw').send_keys('隔壁老趙')
driver.find_element_by_id('su').click()
#獲取信息
print(len(driver.page_source))
print(driver.get_cookies())
print(driver.current_url)
print(driver.name)
#清空輸入框內(nèi)容
driver.find_element_by_id('kw').clear()
#輸入框重新輸入內(nèi)容
driver.find_element_by_id('kw').send_keys('風(fēng)景')
#模擬回車鍵
driver.find_element_by_id('su').send_keys(Keys.RETURN)
#獲取當(dāng)前的url
#截取網(wǎng)頁頁面(生成當(dāng)前的頁面快照并保存)
driver.save_screenshot('baidu.png')
#前進和后退
time.sleep(2)
driver.back() #后退
time.sleep(2)
driver.forward() #前進
#獲取屬性和獲取文本
time.sleep(2)
href = driver.find_element_by_xpath('//h3[@class="t"]/a').get_attribute('href')
title = driver.find_element_by_xpath('//h3[@class="t"]/a').text
print(href)
print(title)
#關(guān)于cookie相關(guān)操作
cookies_dict = {cookie['name']:cookie['value'] for cookie in driver.get_cookies()}
print(cookies_dict)
print(driver.get_cookie('BIDUPSID'))
# driver.delete_all_cookies()
# driver.delete_cookie()
# driver.add_cookie()
###頁面等待
# 因為selenium加載的頁面和瀏覽器一樣會渲染頁面,并且有些網(wǎng)頁加載需要消耗時間
# 這時在頁面加載出來之前去尋找節(jié)點的話,會報異常,所有我們需要添加等待,有時甚至
# 需要前置等待
# 強制等待
# time.sleep(5)
# 隱士等待(設(shè)置等待時間)
# driver.implicitly_wait(10)
# 是指顯示等待:設(shè)置最大的等待時間
# 直到某一條件成立然后繼續(xù)執(zhí)行
# WebDriverWait(driver,10).until(EC.presence_of_element_located(By.ID,''))
#退出
driver.close() #退出當(dāng)前頁面
driver.quit() #退出瀏覽器
頁面的相關(guān)操作
Selenium 的 WebDriver提供了各種方法來尋找元素,假設(shè)下面有一個表單輸入框如
element = driver.find_element_by_id("passwd-id")
獲取name標(biāo)簽值
element = driver.find_element_by_name("user-name")
獲取標(biāo)簽名值
element = driver.find_elements_by_tag_name("input")
也可以通過XPath來匹配
element = driver.find_element_by_xpath("http://input[@id='passwd-id']")
頁面前進和后退
driver.forward() #前進
driver.back() # 后退
Cookies操作
cookies = driver.get_cookies()
cookie_dict = {i['name']:i['value'] for i in cookies}
Selenium 提供了兩種等待方式,一種是隱式等待,一種是顯式等待。
隱式等待是等待特定的時間,如果節(jié)點沒有立即出現(xiàn),隱士等待將一段時間再進行查找 顯式等待是指定一個最長的等待時間,直到條件成立時繼續(xù)執(zhí)行。如果在設(shè)定時間內(nèi)沒加載出來節(jié)點,則返回異常信息,如果加載出來了則返回節(jié)點
from selenium import webdriver
driver = webdriver.Chrome()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")
顯式等待指定某個條件,然后設(shè)置最長等待時間。如果在這個時間還沒有找到元素,那么便會拋出異常了。
from selenium import webdriver
from selenium.webdriver.common.by import By
# WebDriverWait 庫,負責(zé)循環(huán)等待
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions 類,負責(zé)條件出發(fā)
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("http://www.xxxxx.com/loading")
try:
##### 會在這里等待,如果10秒內(nèi) id="myDynamicElement"的標(biāo)簽出現(xiàn)
則返回,如果不出現(xiàn)則報異常
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located(
(By.ID, "myDynamicElement")
)
)
finally:
driver.quit()
異常處理
- 請求超時異常處理
from selenium.common.exceptions import TimeoutException
try:
brower.get(url)
except TimeoutException:
print('Time out')
- 找不到標(biāo)簽的異常處理
from selenium.common.exceptions import NoSuchElementException
try:
brower.find_element_by_id('').click()
print('有標(biāo)簽')
except NoSuchElementException:
print('沒有這個標(biāo)簽')