首先說一下requests+BeautifulSoup對頁面的解析 安裝requests和BeautifulSoup 安裝步驟我在這里就不說了
一、通過requests來讀取網頁信息 可以通過狀態碼來判斷是否成功。
這種requests是最基本的,有的網頁可能會需要cookie、表單提交登錄,還有些網頁需要權限的user-agent、通過IP來限制。這些可以在百度上查一下。https://www.cnblogs.com/wyl-0120/p/10358086.html
2.通過BeautifulSoup來自定義解析網頁
soup = BeautifulSoup(response_data.text, "html.parser")
1.1 把用requests讀取到的網頁文件轉化成BeautifulSoup格式
url_list= soup.find_all("a", href=re.compile('%s' % (www.baidu.com))
1.2 通過find_all來查找a標簽中href屬性包括www.baidu.com的標簽出來(當然BeautifulSoup還有其他的查找方法,但是本人感覺用的地方不多)
得到的是一個bs4.element.Tag的列表,然后遍歷列表。獲取每個Tag的其他屬性
r = re.findall(r"> <b>(.*?)</b>", responseData.text, re.S)
也可以通過這種根據前后標記來獲取數據,這種方法相對更靈活一點。有這兩種,基本上頁面的數據就可以抓取的差不多了
但是有些網站的為了防止爬蟲。做了一些JavaScript腳本代碼。就是說,你加載頁面時,獲取不到頁面的html。只有在觸發腳本代碼事件。才會渲染出真正的html
比如:頁面的上一頁下一頁的操作。如果獲取不到下一頁的html就沒辦法抓取這個網站的全部頁面。這個時候就需要今天的重頭戲了python selenium
二、 python selenium
selenium最初是一個自動化測試工具,而爬蟲中使用它主要是為了解決requests無法直接執行JavaScript代碼的問題 selenium本質是通過驅動瀏覽器,完全模擬瀏覽器的操作,比如跳轉、輸入、點擊、下拉等,來拿到網頁渲染之后的結果,可支持多種瀏覽器
#1.創建Chrome瀏覽器對象,這會在電腦上在打開一個瀏覽器窗口 browser = webdriver.Chrome() browser.get(www.baidu.com')
在創建瀏覽器對象時,需要安裝瀏覽器驅動(版本必須和瀏覽器對應),webdriver.Chrome(path)是有一個參數的,參數就是瀏覽器驅動路徑。(如果把驅動路徑放入打path變量中,就可以不寫參數了)
WebDriver的常用方法
1.最大化瀏覽器 browser.manage().window().maximize(); 2.設置固定的瀏覽器大小 這種方法對采用CSS3和HTML5設計的pc和mobile相互兼容的頁面,通過切換窗口大小來實現pc版和mobile版的控制是極好滴。。。。。。 browser.manage().window().setSize(new Dimension(800, 600)); 3.瀏覽器刷新 browser.navigate().refresh(); 4.瀏覽器前進 browser.navigate().forward(); 5.瀏覽器回退 browser.navigate().back(); 6.cookie設置 browser.manage().addCookie(new Cookie(name, value)); browser.manage().getCookies(); browser.manage().deleteCookie(new Cookie(name, value));
2.1.用BeautifulSoup來處理頁面源代碼
html = browser.page_source soup = BeautifulSoup(html, "lxml")
2.2.用WebDriver來處理頁面源代碼
元素定位
find_element_by_id() # 通過元素ID定位 find_element_by_name() # 通過元素Name定位 find_element_by_class_name() # 通過類名定位 find_element_by_tag_name() # 通過元素TagName定位 find_element_by_link_text() # 通過文本內容定位 find_element_by_partial_link_text() find_element_by_xpath() # 通過Xpath語法定位 find_element_by_css_selector() # 通過選擇器定位
這些都是獲取一個element的,如果想獲取多個,加s(eg:find_elements_by_name())
一般用的多的就是find_elements_by_xpath()這個了。
element_all = browser.find_elements_by_xpath('//div//a[contains(@href, "www.baidu.com")]')
這個是獲取div下的a標簽的href屬性中包括www.baidu.com的全部WebElement,會得到一個WebElement的列表
還有一些find_elements_by_xpath()方法
使用class定位 -- driver.find_element_by_xpath('//input[@class="s_ipt"]') 使用name定位 //form//input[@name="phone"] 【文本定位】使用text()元素的text內容 如://button[text()="登錄"] 【模糊定位】使用contains() 包含函數 如://button[contains(text(),"登錄")]、//button[contains(@class,"btn")] 除了contains不是=等於 【模糊定位】使用starts-with -- 匹配以xx開頭的屬性值;ends-with -- 匹配以xx結尾的屬性值 如://button[starts-with(@class,"btn")]、//input[ends-with(@class,"-special")] 使用邏輯運算符 -- and、or;如://input[@name="phone" and @datatype="m"]
上邊的都是通過相對路徑定位,當然頁有絕對路徑的 -- 以/ 開頭,但是要從根目錄開始,比較繁瑣,一般不建議使用 如:/html/body/div/a
通過遍歷WebElement的列表可以獲取符合條件的WebElement,然后通過WebElement的方法,就能獲取想要的字段的屬性了
2.3.訪問下一個頁面后,想繼續操作原來頁面的功能會報錯 Message: stale element reference: element is not attached to the page document
訪問下個頁面分兩種形式
1.打開新頁面
打開新的頁面的情況,就要操作瀏覽器的句柄了,先獲取新頁面的句柄,然后把新頁面關了。再改回原來頁面的句柄操作
window = browser.window_handles browser.switch_to.window(window[1]) browser.close() browser.switch_to.window(window[0])
如果打開多個瀏覽器句柄和標簽頁的對應關系:
標簽頁順序(按照打開順序):1 2 3 4 5
對應的句柄 :0 4 3 2 1
依次類推
window[0]代表第一個title頁面,window[1]代表最后一個title頁面
2.不打開新頁面
費勁,還沒找到更好的解決方案。目前用了一個很笨的方法
counts_a = len(driver.find_elements_by_class('class name')) for i in range(counts_a): driver.find_element_by_xpath('//a[@class="class name"][i+1]').click()
另外不但進下個頁面docement會變,長時間不操作的話,有可能會有意外的頁面刷新和彈窗
WebElement goChooseShiftBt = browser.findElement(By.xpath(goChooseShift)); // ..... 中間省略了100行代碼 goChooseShiftBt.click(); // 所以要改成
WebElement goChooseShiftBt = browser.findElement(By.xpath(goChooseShift)); goChooseShiftBt.click(); // ..... 中間省略的100行代碼
三 、BrowserMobProxy獲取Ajax請求
browserMobProxy是java寫的一個中間件。允許您操作HTTP請求和響應,捕獲HTTP內容,並將性能數據導出為HAR文件。 BMP作為獨立的代理服務器運行良好,嵌入Selenium測試時尤其有用。下載地址如下https://github.com/lightbody/browsermob-proxy Windows你會有一個.bat(linux就選另一個) 之后通過python安裝BrowserMobProxy
from browsermobproxy import Server # 這里要寫剛下載的.bat路徑 server = Server(r"E:\python\browsermob-proxy-2.1.4\bin\browsermob-proxy.bat")
項目下會有一個server.log日志,如果有問題可以在那里查看
3.1 browserMobProxy整合selenium
selenium已經很強大了,可以解決大部分需求,但是有一些bt網站,訪問的時候,點F12或查看源代碼(Crtl+u)。會發現,源代碼就一些樣式,啥也沒有。那么頁面時怎么渲染的呢?
有前端基礎的同學應該知道。如果打開頁面就加載全部內容,那么相應的時間會加長。那么就有一種技術出來了——> ajax 叫異步請求(有點類似咱們后台的延遲加載,呃...應該就是一個意思)
有了異步請求就可以大大的減少服務器的響應時間了。但是對於咱們python爬蟲來說,簡直就是噩夢。
但是也不是不能獲取的,可以通過瀏覽騎的network模式,來查看都是請求了那些url。但是咱們做的時自動爬取(爬好多數據總不能一個個的點着去看吧?)。但是問題不大,咱們有 過牆梯 啊!
browserMobProxy可以查看network中都是請求了那些url。解決異步加載爬取問題
from time import sleep from browsermobproxy import Server from selenium.webdriver.chrome.options import Options from selenium import webdriver if __name__ == "__main__": # 這里要寫剛下載的.bat路徑 server = Server(r"E:\python\browsermob-proxy-2.1.4\bin\browsermob-proxy.bat") server.start() proxy = server.create_proxy() chrome_options = Options() chrome_options.add_argument('--proxy-server={0}'.format(proxy.proxy)) # https需要加上,要不然回報安全連接問題 chrome_options.add_argument('--ignore-certificate-errors') driver = webdriver.Chrome(options=chrome_options) proxy.new_har(options={ 'captureHeaders': True, 'captureContent': True }) driver.get(url) # 停上幾秒,讓頁面加載完畢,要不然會有漏的 sleep(5) result = proxy.har print(result) for entry in result['log']['entries']: _url = entry['request']['url'] #獲取異步請求的url print(_url) # 根據URL找到數據接口, if "http://www.baidu.com" in _url: _response = entry['response'] _content = _response['content'] # 獲取接口返回內容 print(_response) server.stop() driver.quit()
這樣就可以啦~