網絡爬蟲(14)-動態頁面爬取


1.Ajax介紹

Ajax,全稱為Asynchronous JavaScript and XML,即異步的JavaScript和XML。 它不是一門編程語言,而是利用JavaScript在保證頁面不被刷新、頁面鏈接不改變的情況下與服務器交換數據並更新部分網頁的技術。發送Ajax請求到網頁更新過程,簡單分為以下3步:發送請求;解析內容;渲染網頁。
Ajax具有特殊的請求類型,它叫作xhr。

2.Ajax數據爬取

# 首先,定義一個方法來獲取每次請求的結果。 在請求時,page是一個可變參數,所以我們將它作為方法的參數傳遞進來,相關代碼如下:
from  urllib.parse import  urlencode 
import  requests 
base url = 'https://m.weibo.cn/api/container/getlndex?' 
headers = { 
'Host':  'm.weibo.cn', 
'Referer':'https://m.weibo.cn/u/2830678474',
'User-Agent':'Mozilla/s.o (Macintosh;  Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML,  like Gecko) 
Chrome/58.0.3029.110 Safari/537.36','X-Requested-With ':'XMLHttpRequest',
} 
def get_page(page)':
params = { 
'type':'uid', 
'value':'2830678474', 
'containerid':'1076032830678474', 
'page': page 
}
url = base_url + urlencode(params) 
try: 
    response = requests.get(url, headers=headers) 
    if response.status_code == 200: 
    return response.json() 
except requests.ConnectionError as e: 
    print(' Error',  e.args)
    
# 隨后,我們需要定義一個解析方法,用來從結果中提取想要的信息,比如這次想保存微博的id、正文、贊數、 評論數和轉發數這幾個內容,  那么可以先遍歷cards,然后獲取mblog 中的各個信息,賦值為一個新的字典返回即可:
from  pyquery import  PyQuery as pq 
def parse _page (j son): 
    if json: 
    items  = j son. get(' data ') .get('cards ') 
    for item  in  items: 
        item = item.get('mblog') 
        weibo = {} 
        weibo[ 'id'] = item.get('id') 
        weibo['text'] = pq(item.get('text')). text() 
        weibo['attitudes']  = item.get('attitudes_count') 
        weibo [ 'comments '] = item.get('comments_count') 
        weibo['reposts'] = item.get('reposts_count') 
        yield weibo

# 最后,遍歷一下page,一共10頁,將提取到的結果打印輸出即可:
if name ==  'main': 
    for page in range(l, 11): 
        json = get_page(page) 
        results = parse_page(json) 
    for result in results: 
        print(result)

# 加一個方法將結果保存到MongoDB數據庫:
from  pymongo import MongoClient 
client = MongoClient () 
db = client [ 'weibo' ] 
collection = db['weibo']
def save_to_mongo(result):
    if collection.insert(result):
        print('save to Mongo')

2.Selenium庫

Selenium是一個自動化測試工具,利用它可以驅動瀏覽器執行特定的動作,如點擊、下拉等操作,同時還可以獲取瀏覽器當前呈現的頁面的源代碼,做到可見即可爬。

1)聲明瀏覽器對象

from  selenium import webdriver 
browser = webdri ver. Chrome() 
browser = webdriver. Firefox() 
browser = webdri ver. Edge() 
browser = webdriver. PhantomJS() 
browser= webdriver.Safari() 

# 完成瀏覽器對象初始化並將其賦值為browser 對象。調用 browser對象,讓其執行各個動作以模擬瀏覽器操作。

2)訪問頁面

from  selenium import webdnver 
browser = webdriver.Chrome() 
browser. get (’https://www.taobao.com’ )
print(browser.page_source) 
browser. close() 

# 用get()方法來請求網頁,參數傳入鏈接URL即可。 

3)查找節點

# 單個節點
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
Selenium提供通用方法find_element(),它需要傳入兩個參數: 查找方式By和值。find_element(By.ID,id)
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input_first = browser.find_element(By.ID,'q')
print(input_first)
browser.close()

# 多個節點
要查找所有滿足條件的節點,需要用find_elements()這樣的方法

4)節點交互

Selenium可以驅動瀏覽器來執行一些操作,也就是說可以讓瀏覽器模擬執行一些動作。 

from selenium import webdriver
import time 

browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input = browser.find_element_by_id('q')

# send_keys()方法用於輸入文字
input.send_keys('iPhone')
time.sleep(1)

# clear()方法用於清空文字
input.clear()
input.send_keys('iPad')
button = browser.find_element_by_class_name('btn-search')

# click()方法用於點擊按鈕
button.click()

5)動作鏈

如鼠標拖曳、 鍵盤按鍵等,它們沒有特定的執行對象,這些動作用另一種方式來執行,那就是動作鏈。

- 實現一個節點的拖曳操作,將某個節點從一處拖曳到另外一處

# 首先,打開網頁中的一個拖曳實例,然后依次選中要拖曳的節點和拖曳到的目標節點,接着聲明ActionChains對象並將其賦值為actions變量,然后通過調用actions變量的drag_and_drop()方法,  再調用perform()方法執行動作,此時就完成了拖曳操作
from  selenium import  webdnver 
from  selenium.webdriver import  ActionChains 
browser = webdriver.Chrome() 
url =’http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url) 
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css selector('#draggable') 
target= browser.find_element_by_css_selector('#droppable' ) 
actions = ActionChains(browser) 
actions.drag_and_drop(source, target) 
actions.perform() 

6)JavaScript執行

對於某些操作,Selenium API並沒有提供。 比如,下拉進度條,它可以直接模擬運行JavaScript,
此時使用execute script()方法即可實現,代碼如下:

from selenium import webdriver 
browser= webdriver.Chrome() 
browser. get (’https://www.zhihu.com/explore') 
browser.execute_script('window.scrollTo(o, document.body.scrollHeight)’) 
browser.execute_script('alert(”To Bottom”)') 

# 這里就利用execute script()方法將進度條下拉到最底部,然后彈出alert提示框。

7)獲取節點信息

- 獲取屬性

# 使用get_attribute()方法來獲取節點的屬性
from  selenium import webdriver 
from  selenium.webdriver import  ActionChains 
browser = webdri ver. Chrome() 
url = 'https://www.zhihu.com/explore' 
browser. get ( url) 
logo= browser.find_element_by_id(’zh-top-link-logo’) 
print(logo) 
print(logo.get_attribute(’class' )) 

- 獲取文本值

from  selenium import webdriver 
browser= webdriver.Chrome() 
url =’https://www.zhihu.com/explore’ 
browser. get(url) 
input = browser.find_element by class name('zu-top-add-question’) 
print(input.text) 

- 獲取id、位置、標簽名和大小

from. selenium import  webdnver 
browser = webdriver. Chrome() 
url =’https://www.zhihu.com/explore'
browser.get (url) 
input= browser.find_element_by_class_name(’zu-top-add-question') 
print(input.id)        # 節點id
print(input.location)  # 節點頁面相對位置
print(input.tag_name)  # 標簽名稱
print(input.size)      # 節點大小

8)Frame切換

網頁中有一種節點叫作iframe,也就是子Frame,相當於頁面的子頁面,它的結構和外部網頁的結構完全一致。 Selenium打開頁面后,它默認是在父級Frame里面操作,而此時如果頁面中還有子Frame,它是不能獲取到子Frame里面的節點的。 這時就需要使用switch_to.frame()方法來切換Frame。

import time 
from  selenium import  webdriver 
from  selenium.common.exceptions import  NoSuchElementException 
browser = webdriver.Chrome() 
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable' 
browser.get(url) 
browser.switch_to.frame('iframeresult’) 
try: 
  logo= browser.find_element_by_class_name('logo') 
except NoSuchElementException: 
  print(’NO  LOGO') 
browser.switch_to.parent_frame)
logo = browser. find_element_by_class_name('logo')
print(logo) 
print(logo.text) 

首先通過switch_to. frame()方法切換到子Frame里面,然后嘗試獲取父級Frame 里的logo 節點(這是不能找到的),如果找不到的話,就會拋出NoSuchElementException異常,異常被捕捉之后,就會輸出NO LOGO。 接下來,重新切換回父級Frame,然后再次重新獲取節點,發現此時可以成功獲取了。

- 隱式等待

使用隱式等待執行測試的時候,如果Selenium沒有在DOM中找到節點,將繼續等待,超出設定時間后,則拋什1找不到節點的異常。 換句話說,當查找節點而節點並沒有立即出現的時候,隱式等待將等待一段時間再查找DOM,默認的時間是0。

from  selenium import webdriver 
browser = webdriver.Chrome() 
browser.implicitly_wait (10) 
browser.get(’https://www.zhihu.com/explore' ) 
input = browser. find_element_by_class_name(’zu-top-add-question’) 
print(input) 

- 顯式等待

隱式等中認為固定了等待時間,然而頁面的加載時間會受到網絡條件的影響。
顯式等待方法,它指定要查找的節點,然后指定一個最長等待時間。 如果在規定時間內加載出這個節點,就返回查找的節點;如果到了規定時間依然沒有加載出來,則拋出超時異常。

# 首先引入WebDriverWait這個對象,指定最長等待時間,然后調用它的until()方法,傳入要等待條件expected_conditions。 比如,這里傳入了presence_of_element_located這個條件,代表節  點出現的意思,其參數是節點的定位元組,也就是ID為q的節點搜索框。
- 效果:在10秒內如果ID為q的節點(即搜索框)成功加載出來,就返回該節點;如果超過10秒還沒有加載出來,就拋出異常。

from  selenium import webdriver 
from  selenium.webdriver.common.by import  By 
from  selenium.webdriver.support.ui import WebDriverWait 
from  selenium.webdriver.support import expected_conditions as EC 
browser = webdriver.Chrome() 
browser.get(’https://www.taobao.com/’) 
wait = WebDriverWait(browser, 10) 
input = wait. until(EC. presence_of _element_located( (By. ID,’q’))) 
button = wait.until(EC.element to be clickable((By.CSS_SELECTOR,’.btn search'))) 
print(input, button) 

9)前進、后退

瀏覽器時都有前進和后退功能,Selenium中分別通過forward()、back()方法實現。

import time 
from  selenium import webdnver 
browser = webdriver.Chrome() 
browser. get (’https://www.baidu.com/’) 
browser.get('https://www.taobao.com/’) 
browser.get(’https://www.python.org/’) 
browser.back() 
time.sleep(l) 
browser. forward() 
browser. close() 

10)Cookies

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())
browser.add_cookie({'name':'name','domain':'www.zhihu.com','value':'germey'})
browser.delete_all_cookies()

11)選項卡管理

import  time 
from  selenium import  webdnver 
browser = webdriver. Chrome() 
browser.get(’https://www.baidu.com') 
browser.execute_script(’window. open()’) 
print(browser. window _handles) 
browser.switch_to_window(browser.window_handles[l]) 
browser.get(’https://www.taobao.com') 
time.sleep(l) 
browser.switch_to_window(browser.window_handles(0)) 
browser.get(’https://python.org')

12)異常處理

from  selenium import webdriver 
from  selenium.common.exceptions import  TimeoutException, NoSuchElementExcephon 
browser = webdriver.Chrome() 
try: 
  browser.get('https://www.baidu.com’)
except TimeoutException: 
  print(' Time Out') 
try: 
  browser. find_element_by_id(' hello') 
except NoSuchElementException: 
  print(’No Element’) 
finally:
  browser.close() 

 


免責聲明!

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



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