requests
- requests模塊:是對(duì)urllib的封裝,可以實(shí)現(xiàn)urllib的所有功能
- 并且api調(diào)用更加簡單方便
url, :要請(qǐng)求的目標(biāo)url
params:get請(qǐng)求后面要拼接的參數(shù)
:param method: 要發(fā)起的是什么類型的請(qǐng)求.
:param url: 要請(qǐng)求的目標(biāo)url
:param params: get請(qǐng)求后面要拼接的參數(shù)
:param data: Dictionary, post請(qǐng)求的表單數(shù)據(jù)
:param json: 傳遞json數(shù)據(jù)跟上面的data效果類似
:param headers: (optional) Dictionary 請(qǐng)求頭
:param cookies: (optional) Dict or CookieJar object (設(shè)置cookies信息模擬用戶請(qǐng)求)
:param files: 上傳文件
:param auth: 網(wǎng)站需要驗(yàn)證的信息(賬號(hào)和密碼)
:param timeout: 設(shè)置請(qǐng)求的超時(shí)時(shí)間
:param allow_redirects: bool,是否允許重定向
:param proxies: (optional) Dictionary (設(shè)置代理)
:param verify: Defaults toTrue
.(忽略證書認(rèn)證,默認(rèn)為True表示不忽略)
- requests.session():維持會(huì)話,可以讓我們在跨請(qǐng)求時(shí)保存某些參數(shù)
xpath
xpath:可以在xml中查找信息,對(duì)xml文檔中元素進(jìn)行遍歷和屬性的提取
xml:被設(shè)計(jì)的目的是為了傳輸數(shù)據(jù),結(jié)構(gòu)和html非常相識(shí),是一種標(biāo)記語言
xpath常見的語法:
nodename 選取此節(jié)點(diǎn)的所有子節(jié)點(diǎn)
/ 從根節(jié)點(diǎn)開始查找
// 匹配節(jié)點(diǎn),不考慮節(jié)點(diǎn)的位置
. 選取當(dāng)前節(jié)點(diǎn)
.. 選取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)
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()] 取最后一個(gè)id為123的a標(biāo)簽
a[@id="123"][postion() < 2] 取id為123的前兩個(gè)a標(biāo)簽
pyquery
語法規(guī)則類似于Jquery,可以對(duì)html文本進(jìn)行解析
q = PyQuery(html文檔)
pq('css選擇器')
items():獲取到多個(gè)標(biāo)簽時(shí)棍现,使用items()將PyQuery轉(zhuǎn)換為一個(gè)生成器
然后在使用for in 循環(huán)
filter('css選擇器'):過濾
text():獲取標(biāo)簽的文本
attr('屬性名')獲取屬性值
beautifulsoup
作用是從html/xml中提取數(shù)據(jù),會(huì)載入整個(gè)HTML DOM,比lxml解析器效率要低
re
. :表示匹配除了換行符之外的任意字符
\ :轉(zhuǎn)義字符
[a-z] : 匹配a-z里面的任意一個(gè)字符
\d: 匹配數(shù)字 -> [0-9]
\D: 匹配非數(shù)字 [^\d]
\s: 匹配空白字符(空格,\n,\t...)
\S: 匹配非空白字符
\w: 匹配單詞字符 [A-Za-z0-9_]
\W: 匹配非單子字符
^:匹配以...開頭
$:匹配以....結(jié)尾
():分組
|:或
- 多字符匹配
*:匹配*前面的字符任意次數(shù)
+: 匹配+號(hào)前面的字符至少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ù)
如果某個(gè)子線程的daemon屬性為False,主線程結(jié)束時(shí)會(huì)檢測該子線程是否結(jié)束晦雨,如果該子線程還在運(yùn)行架曹,則主線程會(huì)等待它完成后再退出;
如果某個(gè)子線程的daemon屬性為True闹瞧,主線程運(yùn)行結(jié)束時(shí)不對(duì)這個(gè)子線程進(jìn)行檢查而直接退出绑雄,同時(shí)所有daemon值為True的子線程將隨主線程一起結(jié)束,而不論是否運(yùn)行完成奥邮。
屬性daemon的值默認(rèn)為False万牺,如果需要修改,必須在調(diào)用start()方法啟動(dòng)線程之前進(jìn)行設(shè)置
互斥鎖
當(dāng)多個(gè)線程幾乎同時(shí)修改某一個(gè)共享數(shù)據(jù)的時(shí)候洽腺,需要進(jìn)行同步控制
線程同步能夠保證多個(gè)線程安全訪問競爭資源脚粟,最簡單的同步機(jī)制是引入互斥鎖。
互斥鎖為資源引入一個(gè)狀態(tài):鎖定/非鎖定
某個(gè)線程要更改共享數(shù)據(jù)時(shí)蘸朋,先將其鎖定核无,此時(shí)資源的狀態(tài)為“鎖定”,其他線程不能更改藕坯;直到該線程釋放資源团南,將資源的狀態(tài)變成“非鎖定”,其他的線程才能再次鎖定該資源堕担。互斥鎖保證了每次只有一個(gè)線程進(jìn)行寫入操作曲聂,從而保證了多線程情況下數(shù)據(jù)的正確性霹购。
threading模塊中定義了Lock類,可以方便的處理鎖定:
創(chuàng)建鎖
mutex = threading.Lock()
鎖定
mutex.acquire()
釋放
mutex.release()
鎖的好處:
確保了某段關(guān)鍵代碼只能由一個(gè)線程從頭到尾完整地執(zhí)行
鎖的壞處:
阻止了多線程并發(fā)執(zhí)行朋腋,包含鎖的某段代碼實(shí)際上只能以單線程模式執(zhí)行齐疙,效率就大大地下降了
由于可以存在多個(gè)鎖膜楷,不同的線程持有不同的鎖,并試圖獲取對(duì)方持有的鎖時(shí)贞奋,可能會(huì)造成死鎖
死鎖問題
在線程間共享多個(gè)資源的時(shí)候赌厅,如果兩個(gè)線程分別占有一部分資源并且同時(shí)等待對(duì)方的資源,就會(huì)造成死鎖轿塔。
盡管死鎖很少發(fā)生特愿,但一旦發(fā)生就會(huì)造成應(yīng)用的停止響應(yīng)
多進(jìn)程
進(jìn)程:一個(gè)程序運(yùn)行起來后,代碼+用到的資源 稱之為進(jìn)程勾缭,它是操作系統(tǒng)分配資源的基本單元揍障。
不僅可以通過線程完成多任務(wù),進(jìn)程也是可以的
multiprocessing模塊就是跨平臺(tái)版本的多進(jìn)程模塊俩由,提供了一個(gè)Process類來代表一個(gè)進(jìn)程對(duì)象毒嫡,這個(gè)對(duì)象可以理解為是一個(gè)獨(dú)立的進(jìn)程,可以執(zhí)行另外的事情
Queue的使用
Queue本身是一個(gè)消息列隊(duì)程序
Queue.qsize():返回當(dāng)前隊(duì)列包含的消息數(shù)量幻梯;
Queue.empty():如果隊(duì)列為空兜畸,返回True,反之False 碘梢;
Queue.full():如果隊(duì)列滿了咬摇,返回True,反之False;
Queue.get(block, timeout):獲取隊(duì)列中的一條消息痘系,然后將其從列隊(duì)中移除菲嘴,block默認(rèn)值為True;
1)如果block使用默認(rèn)值汰翠,且沒有設(shè)置timeout(單位秒)龄坪,消息列隊(duì)如果為空,此時(shí)程序?qū)⒈蛔枞ㄍT谧x取狀態(tài))复唤,直到從消息列隊(duì)讀到消息為止健田,如果設(shè)置了timeout,則會(huì)等待timeout秒佛纫,若還沒讀取到任何消息妓局,則拋出"Queue.Empty"異常;
2)如果block值為False呈宇,消息列隊(duì)如果為空好爬,則會(huì)立刻拋出"Queue.Empty"異常;
Queue.get_nowait():相當(dāng)Queue.get(False)甥啄;
Queue.put(item,block,timeout):將item消息寫入隊(duì)列存炮,block默認(rèn)值為True;
1)如果block使用默認(rèn)值,且沒有設(shè)置timeout(單位秒)穆桂,消息列隊(duì)如果已經(jīng)沒有空間可寫入宫盔,此時(shí)程序?qū)⒈蛔枞ㄍT趯懭霠顟B(tài)),直到從消息列隊(duì)騰出空間為止享完,如果設(shè)置了timeout灼芭,則會(huì)等待timeout秒,若還沒空間般又,則拋出"Queue.Full"異常彼绷;
2)如果block值為False,消息列隊(duì)如果沒有空間可寫入倒源,則會(huì)立刻拋出"Queue.Full"異常苛预;
Queue.put_nowait(item):相當(dāng)Queue.put(item, False);
- Queue實(shí)例以及在多進(jìn)程間的使用
multiprocessing.Pool常用函數(shù)解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式調(diào)用func(并行執(zhí)行笋熬,堵塞方式必須等待上一個(gè)進(jìn)程退出才能執(zhí)行下一個(gè)進(jìn)程)热某,args為傳遞給func的參數(shù)列表,kwds為傳遞給func的關(guān)鍵字參數(shù)列表胳螟;
close():關(guān)閉Pool昔馋,使其不再接受新的任務(wù);
terminate():不管任務(wù)是否完成糖耸,立即終止秘遏;
join():主進(jìn)程阻塞,等待子進(jìn)程的退出嘉竟, 必須在close或terminate之后使用邦危;
進(jìn)程與線程的對(duì)比
進(jìn)程、線程對(duì)比 功能
進(jìn)程舍扰,能夠完成多任務(wù)倦蚪,比如 在一臺(tái)電腦上能夠同時(shí)運(yùn)行多個(gè)QQ
線程,能夠完成多任務(wù)边苹,比如 一個(gè)QQ中的多個(gè)聊天窗口
定義的不同
進(jìn)程是系統(tǒng)進(jìn)行資源分配基本單位.
線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.
線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享所在進(jìn)程所擁有的全部資源
區(qū)別
一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程.
線程的劃分尺度小于進(jìn)程(資源比進(jìn)程少)陵且,使得多線程程序的并發(fā)性高。
進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元个束,而多個(gè)線程共享內(nèi)存慕购,從而極大地提高了程序的運(yùn)行效率
線線程不能夠獨(dú)立執(zhí)行,必須依存在進(jìn)程中
優(yōu)缺點(diǎn)
線程和進(jìn)程在使用上各有優(yōu)缺點(diǎn):線程執(zhí)行開銷小茬底,但不利于資源的管理和保護(hù)沪悲;而進(jìn)程正相反。
使用場景:
多進(jìn)程常用來處理計(jì)算密集型任務(wù): 計(jì)算密集型任務(wù)的特點(diǎn):是要進(jìn)行大量的計(jì)算阱表,消耗CPU資源殿如,比如計(jì)算圓周率昌妹、對(duì)視頻進(jìn)行高清解碼等等,全靠CPU的運(yùn)算能力握截。計(jì)算密集型任務(wù)可以用多任務(wù)完成,但是任務(wù)越多烂叔,花在任務(wù)切換的時(shí)間就越多谨胞,CPU執(zhí)行任務(wù)的效率就越低,所以蒜鸡,要最高效地利用CPU胯努,計(jì)算密集型任務(wù)同時(shí)進(jìn)行的數(shù)量應(yīng)當(dāng)?shù)扔贑PU的核心數(shù)。
多線程常用來處理IO密集型任務(wù): IO密集型:涉及到網(wǎng)絡(luò)逢防、磁盤IO的任務(wù)都是IO密集型任務(wù)叶沛,特點(diǎn)是CPU消耗很少,任務(wù)的大部分時(shí)間都在等待IO操作完成(因?yàn)镮O的速度遠(yuǎn)遠(yuǎn)低于CPU和內(nèi)存的速度)忘朝。但是也要切記灰署,在執(zhí)行多任務(wù)時(shí),并不是越多線程越好局嘁。
SELENIUM
Selenium是一個(gè)Web的自動(dòng)化測試工具溉箕,最初是為網(wǎng)站自動(dòng)化測試而開發(fā)的,類型像我們玩游戲用的按鍵精靈悦昵,可以按指定的命令自動(dòng)操作肴茄,不同是Selenium 可以直接運(yùn)行在瀏覽器上,它支持所有主流的瀏覽器(包括PhantomJS這些無界面的瀏覽器)但指。 Selenium 可以根據(jù)我們的指令寡痰,讓瀏覽器自動(dòng)加載頁面,獲取需要的數(shù)據(jù)棋凳,甚至頁面截屏拦坠,或者判斷網(wǎng)站上某些動(dòng)作是否發(fā)生。
Selenium 自己不帶瀏覽器贫橙,不支持瀏覽器的功能贪婉,它需要與第三方瀏覽器結(jié)合在一起才能使用。但是我們有時(shí)候需要讓它內(nèi)嵌在代碼中運(yùn)行卢肃,所以我們可以用一個(gè)叫 PhantomJS 的工具代替真實(shí)的瀏覽器疲迂。
主要使用的方法和代碼如下
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ù)對(duì)象
# 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è)置頁面的加載超時(shí)時(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é)點(diǎn)
# driver.find_element_by_class_name():根據(jù)類名定位節(jié)點(diǎn)
# driver.find_element_by_partial_link_text():根據(jù)部分文本內(nèi)容定位節(jié)點(diǎn)
# driver.find_element_by_css_selector():根據(jù)css選擇器定位節(jié)點(diǎn)
# driver.find_element_by_link_text():根據(jù)完整文本定位節(jié)點(diǎn)
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')
#前進(jìn)和后退
time.sleep(2)
driver.back() #后退
time.sleep(2)
driver.forward() #前進(jìn)
#獲取屬性和獲取文本
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()
###頁面等待
# 因?yàn)閟elenium加載的頁面和瀏覽器一樣會(huì)渲染頁面,并且有些網(wǎng)頁加載需要消耗時(shí)間
# 這時(shí)在頁面加載出來之前去尋找節(jié)點(diǎn)的話,會(huì)報(bào)異常,所有我們需要添加等待,有時(shí)甚至
# 需要前置等待
# 強(qiáng)制等待
# time.sleep(5)
# 隱士等待(設(shè)置等待時(shí)間)
# driver.implicitly_wait(10)
# 是指顯示等待:設(shè)置最大的等待時(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è)下面有一個(gè)表單輸入框如
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']")
頁面前進(jìn)和后退
driver.forward() #前進(jìn)
driver.back() # 后退
Cookies操作
cookies = driver.get_cookies()
cookie_dict = {i['name']:i['value'] for i in cookies}
Selenium 提供了兩種等待方式尤蒿,一種是隱式等待,一種是顯式等待幅垮。
隱式等待是等待特定的時(shí)間腰池,如果節(jié)點(diǎn)沒有立即出現(xiàn),隱士等待將一段時(shí)間再進(jìn)行查找 顯式等待是指定一個(gè)最長的等待時(shí)間,直到條件成立時(shí)繼續(xù)執(zhí)行。如果在設(shè)定時(shí)間內(nèi)沒加載出來節(jié)點(diǎn),則返回異常信息,如果加載出來了則返回節(jié)點(diǎn)
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")
顯式等待指定某個(gè)條件示弓,然后設(shè)置最長等待時(shí)間讳侨。如果在這個(gè)時(shí)間還沒有找到元素,那么便會(huì)拋出異常了奏属。
from selenium import webdriver
from selenium.webdriver.common.by import By
# WebDriverWait 庫跨跨,負(fù)責(zé)循環(huán)等待
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions 類,負(fù)責(zé)條件出發(fā)
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("http://www.xxxxx.com/loading")
try:
##### 會(huì)在這里等待囱皿,如果10秒內(nèi) id="myDynamicElement"的標(biāo)簽出現(xiàn)
則返回勇婴,如果不出現(xiàn)則報(bào)異常
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located(
(By.ID, "myDynamicElement")
)
)
finally:
driver.quit()
異常處理
- 請(qǐng)求超時(shí)異常處理
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('沒有這個(gè)標(biāo)簽')