python3.8通過python selenium+requests+BeautifulSoup+ BrowserMobProxy對頁面進行徹底爬取


首先說一下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()

這樣就可以啦~

 

 

 


  


免責聲明!

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



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