- Python 3.6.6
- pip 10.0.0:為Python內建的套件管理
- jupyter notebook 4.4.0
- 常見剖析 HTML 原始碼的方式有三種
- 正則表示式(Regular Expression):容易被網站的小改動影響
- 當成 HTML 處理
- Beautiful Soup(簡稱 bs4)是最常看到用來操作 HTML 的套件
html.parser
來剖析 HTML- 搜尋方法
- 用
.
直接取到節點 - 字串:指定要搜尋的標籤名稱
# 搜尋標籤 "b" soup.find_all('b') # [<b>The Dormouse's story</b>]
- 正規表示式:利用 Python re 物件的 search() 方法來搜尋符合的標籤名稱
# 搜尋以 "b" 開頭的標籤 import re for tag in soup.find_all(re.compile("^b")): print(tag.name) # body # b
- 清單:指定多個要搜尋的標籤名稱
- 指令:find_all(name, attrs, recursive, string, limit, **kwargs)
- 範例
# 搜尋標籤 "a" 和 "b" soup.find_all(["a", "b"])
- 參數說明
- name:帶入前面介紹的「過濾器」
- attrs:傳入 dict 物件,用屬性來過濾
- recursive:使用布林值(預設是 True),用來設定是否要遞迴往下找
- string:帶入「過濾器」,用標籤的文字內容來過濾
- limit:指定要回傳幾個結果
- keyword arguments:跟 attrs 參數一樣是用屬性來過濾,絕大多數的情況下用 kwargs 就可以,只有一些特殊狀況(保留字、屬性名稱與方法參數名稱相同、kebab-case)會需要用 attrs 參數來處理
- 範例
- 指令:find_all(name, attrs, recursive, string, limit, **kwargs)
- 方法:定義一個會回傳布林的方法物件來判斷是否要傳回標籤
# 判斷標籤是否定義 class 屬性且無定義 id 屬性 tag.has_attr('class') and not tag.has_attr('id')
- 用
- 支援
lxml
和html5lib
- 一般建議使用比較快的 lxml,使用 XPath 定位資料
- 安裝套件
pip install lxml
- 方法:用 lxml 的 etree.HTML() 方法載入 HTML 原始資料後,可以用 .xpath() 方法來執行 XPath 查詢
- XPath 常用語法
- 選擇節點
語法 說明 語法 說明 node-name 選擇名稱等於 node-name 的節點 / 選擇直屬於當前節點的所有節點(子節點) // 選擇當前節點下所有節點(子孫節點) . 選擇當前節點 .. 選擇上一層節點(父節點) @ 選擇屬性 - 範例說明:HTML 原始內容
- 基本
- /html:取得 html 標籤(以 / 開頭代表從根節點開始找)
- /html/body/a:取得 body 下所有 a 標籤
- //a:取得所有 a 標籤
- /html/body//a:取得 body 下所有 a 標籤
- //a/@href:取得所有 a 標籤的 href 屬性
- 進階判斷式(predicates)
- /html/body//a[1]:取得 body 下第一個 a 標籤
- /html/body//a[last() - 1]:取得 body 下最後一個 a 標籤
- /html/body//a[position() < 3]:取得 body 下前兩個 a 標籤
- //p[@class]:取得有定義 class 屬性的 p 標籤
- //p[@class='title']:取得 class 屬性值為 title 的 p 標籤
- 選取任意節點:
*
:任意標籤@*
:任意屬性|
:一次查詢多組路徑- 範例
- /html/body/*:取得 body 標籤的全部子節點
- /html/body//*:取得 body 下全部標籤
- //p[@*]:取得至少有定義一個屬性的 p 標籤
- //p | //a:一次取得全部 p 標籤和 a 標籤
- 基本
- 選擇節點
- 載入 HTML 字串
prettify()
:回傳剖析器處理完後格式化的字串- 注意同樣的原始碼在不同剖析器可能會有不同的結果
- Beautiful Soup(簡稱 bs4)是最常看到用來操作 HTML 的套件
- 當成 XML 處理
- 說明:可「自動」瀏覽全球資訊網的網路機器人,許多的搜尋入口網站(如 Google),都會透過網路爬蟲收集網路上的各種資訊,進一步分析後成為使用者搜尋的資料,許多開發者也會自行開發不同的爬蟲程式,進行大數據收集與分析
- 類型
- 靜態爬蟲:網站完成一個請求(request)與回應(response) 後,用戶端即不再與伺服器有任何的交流,所有的互動都只與瀏覽器的網頁互動,資訊不會傳遞到後端伺服器
- 動態爬蟲:網站會依照使用者的行為不斷的與伺服器進行交流,必須要知道網站需要什麼「資訊」,提供正確的資訊,才能取得所需要的資料
- 使用爬蟲的禮儀
- 不造成網站伺服器的負擔:每次爬取資料時,設定適當的等待延遲
- 確認網站是否有提供 API:節省讀取與分析網站 HTML 的時間
- 注意 robots.txt:規範一個網站允許什麼樣的 User-Agent 訪問,也會規範 Crawl-delay 訪問間隔時間,如果 Crawl-delay 設定 1,表示這個網站期望每次訪問的時間間隔一秒鐘
- 反爬蟲機制
機制 說明 作法 破解難度 判斷瀏覽器 headers 資訊 利用 headers 判斷來源是否合法,headers 通常會由瀏覽器自動產生,直接透過程式所發出的請求預設沒有 headers 只要能透過爬蟲程式,送出模擬瀏覽器的 headers 資訊,就能進行破解 低 清空 window.navigator 有些反爬蟲的網頁,會檢測瀏覽器的 window.navigator 是否包含 webdriver 屬性,在正常使用瀏覽器的情況下,webdriver 屬性是 undefined,一旦使用了 selenium 函式庫,這個屬性就被初始化為 true 程式使用 selenium webdriver 的 execute_cdp_cmd 的方法,將 webdriver 設定為 undefined (詳如 selenium 說明) 使用動態頁面 將網頁內容全部由動態產生,大幅增加爬蟲處理網頁結構的複雜度 只要確認動態頁面的架構,就能進行破解,如果打開的網頁是動態頁面,「檢視網頁原始碼」時看到的結構往往會很簡單,通常都只會是一些簡單的 HTML、CSS 和壓縮過的 js 文件 中低 加入使用者行為判斷 在網頁的某些元素,加入使用者行為的判斷,例如滑鼠移動順序、滑鼠是否接觸...等,增加爬蟲處理的難度 確認頁面加入的使用者行為,就能模擬並進行破解,
如:有些網頁會在按鈕加上「滑鼠碰觸」的保護,如果不是真的用滑鼠碰觸,只是用程式撰寫「點擊」指令,就會被當作爬蟲而被阻擋,模故擬出先碰觸元素,再進行點擊的動作,藉此突破這個反爬蟲的機制(詳如模擬點擊說明)
如:有些網頁也會判斷使用者刷新網頁的時間(通常使用者不會在極短的時間內連續刷新),這時也可以使用 time 函式庫的 sleep 方法讓網頁有所等待,避開這個檢查機制中 提交使用者授權 在使用者登入時,會將使用者的授權(token)加入瀏覽器的 Cookie 當中,藉由判斷 Cookie 確認使用者是否合法 只要知道 request 與 response 的機制後,取得 Cookie 內的 token 就能破解 中 破解驗證碼 相當常見的驗證機制,可相當程度的防堵惡意的干擾與攻擊,對於非人類操作與大量頻繁操作都有不錯的防範機制(如防堵高鐵搶票、演唱會搶票...等) 必須搭配一些 AI 來處理圖形、數字、文字的識別,通常只要能識別驗證碼就能破解,要破解一般驗證碼,需要先將網頁上的驗證碼圖片下載,再將圖片提交到 2Captcha 服務來幫我們進行辨識 高 破解代理伺服器與第三方 IP 封鎖 針對惡意攻擊的 IP 進行封鎖 通常必須更換 IP 或更換代理伺服器才能破解,許多網站上也有提供免費的 Proxy IP,以 Free Proxy List 網站為例,就能取得許多免費的 Proxy IP 高
- 搭配使用工具
- Webdriver
- WebDriver 是用來執行並操作瀏覽器的 API 介面,每一個瀏覽器都會有各自對應的驅動程式(driver),Selenium 會透過 WebDriver 來直接對瀏覽器進行操作,將所支援的瀏覽器進行自動化作業,就如同真的使用者在操作
- 不同瀏覽器會有不同的 driver,如Chrome、Edge、Firefox、Safari,需下載目前瀏覽器版本的 Webdriver
- 下載版本查詢
- Chromedriver:其他瀏覽器類似
# 載入需要的套件 from selenium import webdriver # 開啟瀏覽器視窗(Chrome) # 方法一:執行前需開啟 chromedriver.exe 且與執行檔在同一個工作目錄 driver = webdriver.Chrome('./chromedriver') # 指向 chromedriver 的位置 # 方法二:或是直接指定 exe 檔案路徑 driver = webdriver.Chrome('桌面\chromedriver') # get():輸入網址,即可前往特定網頁 driver.get('https://www.google.com') # 更改網址以前往不同網頁 # close():可關閉目前網頁視窗 driver.close() # 關閉瀏覽器視窗
- 額外工具
- 網頁檢視器:網頁中看得到的內容一定抓得下來
- Windows:請按 f12、ctrl+shift+i
- macOS:請按 option+command+c
- Webdriver
- 套件
- Selenium
- 介紹:可模擬出使用者在瀏覽器的所有操作行為(點擊按鈕、輸入帳號密碼、捲動捲軸...等),因此除了爬蟲的應用,也常作為「自動化測試」使用的工具
- 優點:可模擬使用者的動作,進行登入後爬取資料或滾動卷軸,並且能夠執行 JavaScript 程式碼
- 指令
from selenium import webdriver # 請求頭信息偽裝為瀏覽器,可以更好地請求數據信息 user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15' opt = webdriver.ChromeOptions() # 加入 headers 資訊 opt.add_argument('--user-agent=%s' % user_agent) driver = webdriver.Chrome('./chromedriver', options=opt) # 清空 window.navigator driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", { "source": """ Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) """ }) driver.get('要爬的網址')
- 使用規則
- 取得網頁元素:兩種函數找出 WebElement
- find_element:抓取符合條件的第一個項目,可搭配 By 方法
- find_elements:抓取所有符合條件的項目,並回傳成 list
- 八種方法
- ID = id
- CLASS_NAME = class_name
- 透過標籤的 class 屬性搜尋
- 字串內有空格的話要改為「.」
- NAME = name
- LINK_TEXT = link_text
- 透過連結標籤的文字搜尋
- PARTIAL_LINK_TEXT = partial_link_text
- TAG_NAME = tag_name
- 使用 TAG 選擇器特別要注意的是,HTML 標籤時常重複,因此 TAG 選擇器通常適用於抓取大框架的網頁元素再做細部搜尋
- XPATH = xpath
- 用於在 XML 文檔中定位節點的語言(想像網頁是圖書館,而各個網頁元素是書籍,XPath 就有點類似於目錄編號,可以直接查找)
- 原因:當想要查找的元素沒有合適的 id 或 name 屬性時,可以使用 XPath 以絕對路徑(不建議使用)定位元素,也可以利用已知特殊 id 或 name 屬性的元素的相對路徑定位
- XPath 包含來自 HTML 所有元素的位置(絕對路徑),因此,僅對網頁進行一點點調整就可能導致失敗(超級容易失敗,要不斷維護)
- 步驟
- 打開網頁檢視器,找到目標網頁元素的內容
- 在內容上點擊右鍵 → Copy→Copy (full) XPath,獲取絕對或相對 XPath
- 將複製下來的 XPath 貼上
- 範例:
- CSS_SELECTOR = css_selector
- 重要
- 「/」改寫成「>」
- 「//」改寫成「 (空格)」
- 用 id 查找「#」
- 用 classname 查找「.」
- 參考網頁:CSS Selectors
- 重要
- 取得標籤的資訊
- 取得標籤的內部文字
element = driver.find_element(搜尋欄位, '搜尋條件') element.text
- 取得標籤的某個屬性
element = driver.find_element(搜尋欄位, '搜尋條件') element.get_attribute('屬性名稱')
- 模擬使用者點擊標籤
element = driver.find_element(搜尋欄位, '搜尋條件') element.click()
- 取得標籤的內部文字
- 操作網頁元素
- 方法
方法 ActionChains 參數 說明 方法 ActionChains 參數 說明 click() element 按下滑鼠左鍵 click_and_hold() element 滑鼠左鍵按著不放 double_click() element 連續按兩下滑鼠左鍵 context_click() element 按下滑鼠右鍵 (需搭配指定元素定位) drag_and_drop() source, target 點擊 source 元素後,移動到 target 元素放開 drag_and_drop_by_offset() source, x, y 點擊 source 元素後,移動到指定的座標位置放開 release() element 放開滑鼠 move_by_offset() x, y 移動滑鼠座標到指定位置 move_to_element() element 移動滑鼠到某個元素上 move_to_element_with_offset() element, x, y 移動滑鼠到某個元素的相對座標位置 send_keys() values 送出某個鍵盤按鍵值 send_keys_to_element() element, values 向某個元素發送鍵盤按鍵值 key_down() value 按著鍵盤某個鍵 key_up() value 放開鍵盤某個鍵 reset_actions() 清除儲存的動作 (實測沒有作用,查訊後是 Bug) pause() seconds 暫停動作 perform() 執行儲存的動作 - 要使用這些方法的方式有兩種
- 第一種「針對指定元素呼叫方法」:只要針對指定的元素,呼叫指定的方法,就會執行對應的動作,只能使用 click、send_keys等
from selenium import webdriver from time import sleep driver = webdriver.Chrome('./chromedriver') driver.get('https://example.oxxostudio.tw/python/selenium/demo.html') a = driver.find_element_by_id('a') add = driver.find_element_by_id('add') a.click() # 點擊按鈕 A,出現 a 文字 sleep(1) add.click() # 點擊 add 按鈕,出現 數字 1 add.click() # 點擊 add 按鈕,出現 數字 2 sleep(1) add.click() # 點擊 add 按鈕,出現 數字 3 sleep(1) add.click() # 點擊 add 按鈕,出現 數字 4
- 第二種「使用ActionChains」:將所有需要執行的方法串成「鏈」,全部完成後執行 perform() 執行所有的過程
from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains driver = webdriver.Chrome('./chromedriver') driver.get('https://example.oxxostudio.tw/python/selenium/demo.html') a = driver.find_element_by_id('a') add = driver.find_element_by_id('add') actions = ActionChains(driver) # 使用 ActionChains 的方式 actions.click(a).pause(1) # 點擊按鈕 A,出現 a 文字後,暫停一秒 actions.double_click(add).pause(1).click(add).pause(1).click(add) # 連點 add 按鈕,等待一秒後再次點擊,等待一秒後再次點擊 actions.perform() # 執行儲存的動作
- 第一種「針對指定元素呼叫方法」:只要針對指定的元素,呼叫指定的方法,就會執行對應的動作,只能使用 click、send_keys等
- 取得網頁元素的內容
- text:元素的內容文字
- get_attribute:元素的某個 HTML 屬性值
- id:元素的 id
- tag_name:元素的 tag 名稱
- size:元素的長寬尺寸
- screenshot:將某個元素截圖並儲存為 png
- is_displayed():元素是否顯示在網頁上
- is_enabled():元素是否可用
- is_selected():元素是否被選取
- parent:元素的父元素。
- 方法
- 取得網頁元素:兩種函數找出 WebElement
- Requests
- 介紹:對網路發動請求的套件,可實作對網頁做 get、post 等 HTTP 協定的行為,請求網站獲取網頁數據
- 指令
import requests url = '要爬的網址' res = requests.get(url) # 返回 200:請求成功 # 請求頭信息偽裝為瀏覽器,可以更好地請求數據信息 headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'} res = requests.get(url, headers=headers) res.encoding = 'utf8' print(res.text)
- 類型
HTTP 方法 requests 方法 說明 備註 GET requests.get(url) 向指定資源提交請求,可額外設定 params 參數字典 就像明信片,需要撰寫目的地的地址及內容,其中的地址就像是請求的網址,而內容就像是接在網址後面的參數(querystring),提交的參數會放在標頭中傳送(公開) POST requests.post(url) 向指定資源提交請求,可額外設定 data 參數字典 就像一般的信件,需撰寫目的地的地址,而信件內容會在信封中,提交的參數會放在內容中傳送(隱密) PUT requests.put(url) 向指定資源提供最新內容,可額外設定 data 參數字典 DELETE requests.delete(url) 請求刪除指定的資源 HEAD requests.head(url) 請求提供資源的回應標頭(不含內容) OPTIONS requests.options(url) 請求伺服器提供資源可用的功能選項 - Response 物件的屬性與方法
- 說明:當伺服器收到 requests HTTP 方法所發出的請求後,會傳回一個 Response 物件,物件裡包含伺服器回應的訊息資訊,可以透過下列的屬性與方法,查詢相關內容(bytes 表示資料以 bytes 表示,str 以字串表示,dict 以字典表示)
Response 物件 說明 Response 物件 說明 url 資源的 URL 位址 content 回應訊息的內容(bytes) text 回應訊息的內容字串(str) raw 原始回應訊息串流(bytes) status_code 回應的狀態(int) encoding 回應訊息的編碼 headers 回應訊息的標頭(dict) cookies 回應訊息的 cookies(dict) history 請求歷史(list) json() 將回應訊息進行 JSON 解碼後回傳(dict) rasise_for_status() 檢查是否有例外發生,如果有就拋出例外
- 說明:當伺服器收到 requests HTTP 方法所發出的請求後,會傳回一個 Response 物件,物件裡包含伺服器回應的訊息資訊,可以透過下列的屬性與方法,查詢相關內容(bytes 表示資料以 bytes 表示,str 以字串表示,dict 以字典表示)
- 傳遞參數
- headers
- 用途:讓瀏覽器向伺服器表明自己的身分,有些 HTTP 伺服器僅允許來自普通瀏覽器的請求,而不接受來自程式腳本的請求
- 經常用於「偽裝」User-Agent
- Mozilla Firefox 的 header 的值為 'Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11'
- urllib 的 header 的值為 'Python-urllib/2.6'
- 執行方式:Mozilla、AppleWebKit、Chrome,解析網頁:用 text/html 的方式,以 UTF-8 的格式去做解析
headers = { 'content-type': 'text/html; charset=UTF-8', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36' }
- cookies:設定 Request 中的 cookie(dict)
- auth:支持 HTTP 認證功能(tuple)
- json: JSON 格式的數據,作為 Request 的內容
- files:傳輸文件(dict)
- timeout:設定超時時間,以「秒」為單位
- proxies:設定訪問代理伺服器,可以增加認證(dict)
- allow_redirects:True/False,預設 True,意即重新定向
- stream:True/False,預設 True,意即獲取內容立即下載
- verify:True/False,預設 True,意即認證 SSL
- cert:本機 SSL 路徑
- headers
- BeautifulSoup
- 介紹
- 借助網頁的結構特性來解析網頁的工具
- 分析網頁的 HTML 與 XML 文件,並將分析的結果轉換成「網頁標籤樹」(tag) 的型態,讓資料讀取方式更接近網頁的操作語法,處理起來也更為便利
- 通常會搭配 requests 爬取網頁內容一併使用
- 指令
import requests from bs4 import BeautifulSoup url = 'https://water.taiwanstat.com/' web = requests.get(url) # 取得網頁內容 soup = BeautifulSoup(web.text, 'html.parser') # 轉換成標籤樹 title = soup.title # 取得 title print(soup.find_all('a')) # 等同於下方的 soup('a') print(soup('a')) # 等同於上方的 find_all('a') infos = soup.select('路徑') # 路徑提取方式:在固定位置右鍵->copy->copy selector
- 說明
- 網頁是由「標籤」的語法所構成,標籤 (tag) 指的是由「<」和「>」包覆的代碼
- 解析器:html5lib 的容錯率比 html.parser 高,但解析速度比較慢
- Python 本身內建「html.parser」的解析器
- 另外安裝「html5lib」解析器不需要 import,安裝後就可以使用
pip install html5lib
- Beautiful Soup 的方法
方法 說明 方法 說明 select() 以 CSS 選擇器的方式尋找指定的 tag find_all()、find() 以所在的 tag 位置,尋找內容裡所有的 tag 或第一個指定的 tag find_parents()、find_parent() 以所在的 tag 位置,尋找父層所有指定的 tag 或第一個找到的 tag find_next_siblings()、find_next_sibling() 以所在的 tag 位置,尋找同一層後方所有指定的 tag 或第一個找到的 tag find_previous_siblings()、find_previous_sibling() 以所在的 tag 位置,尋找同一層前方所有指定的 tag 或第一個找到的 tag find_all_next()、find_next() 以所在的 tag 位置,尋找後方內容裡所有指定的 tag 或第一個找到的 tag find_all_previous()、find_previous() 所在的 tag 位置,尋找前方內容裡所有指定的 tag 或第一個找到的 tag - Beautiful Soup 方法的參數
- string:搜尋 tag 包含的文字
- limit:搜尋 tag 後只回傳多少個結果
- recursive:預設 True,會搜尋內容所有層,設定 False 只會搜尋下一層
- id:搜尋 tag 的 id
- class_:搜尋 tag class,因為 class 為 Python 保留字,所以後方要加上底線
- href:搜尋 tag href
- attrs:搜尋 tag attribute 屬性
- 取得並輸出內容
- .get_text():輸出 tag 的內容
- [屬性]:輸出 tag 裡某個屬性的內容
url = 'https://www.iana.org/domains/' web = requests.get(url) soup = BeautifulSoup(web.text, 'html.parser') print(soup.find('a').get_text()) # 輸出第一個 a tag 的內容 print(soup.find('a')['href']) # 輸出第一個 a tag 的 href 屬性內容
- 介紹
- Lxml
- 指令:
From lxml import etree Html = etree.HTML(text) infos = Html.xpath('路徑') #路徑提取方式:在固定位置右鍵->copy->copy xpath
- 介紹:Lxml 為 XML 解析庫,可修正 HTML 代碼,形成結構化的 HTML 結構
- 範例:詳如「爬蟲_股票資料_xpath.ipynb」之 HTML
- 指令:
- 下載特定網址資料
- 一般格式
import urllib.request as req url = 網址 with req.urlopen(url) as response: data = response.read().decode('utf-8') # 取得網址的原始碼(HTML、CSS、JS) print(data)
- JSON
import urllib.request as req import json url = 'https://data.taipei/api/v1/dataset/296acfa2-5d93-4706-ad58-e83cc951863c?scope=resourceAquire' with req.urlopen(url) as response: data = json.load(response) # 利用 json 模組處理 json 資料格式 print(data)
- 範例:詳如「爬蟲_簡易說明」之範例四~六
- 一般格式
- Selenium
- requests:
- 範例一 :【PTT 資訊版】爬取文章標題
- import Python套件
import requests from bs4 import BeautifulSoup
- 將網頁 Get 下來
r = requests.get('https://www.ptt.cc/bbs/MobileComm/index.html') #將此頁面的HTML GET下來 print(r.text) #印出HTML
- 將抓下來的資料用 Beautifulsoup4 轉為 HTML 的 parser,想選取的網頁裡的文章標題,故 soup.select 中放的是 div.title a
soup = BeautifulSoup(r.text, 'html.parser') #將網頁資料以html.parser sel = soup.select('div.title a') #取HTML標中的 <div class="title"></div> 中的<a>標籤存入sel
- 最後寫一個迴圈將爬下來的文章標題印出來
for s in sel: print(s['href'], s.text)
- 範例:詳如「爬蟲_簡易說明.ipynb」之範例一
- import Python套件
- 範例二:【PTT Joke版】爬取多頁資料
- 觀察下一頁按鈕的HTML標籤內容,發現上一頁按鈕的 a 標籤中有上一頁的網址為「/bbs/joke/index8140.html」
r = requests.get('https://www.ptt.cc/bbs/joke/index.html') soup = BeautifulSoup(r.text, 'html.parser') u = soup.select('div.btn-group.btn-group-paging a')#上一頁按鈕的a標籤 url = 'https://www.ptt.cc'+ u[1]['href'] #組合出上一頁的網址
- 藉由迴圈來重複GET網頁
url = 'https://www.ptt.cc/bbs/joke/index.html' for i in range(3): #往上爬3頁 r = requests.get(url) soup = BeautifulSoup(r.text, 'html.parser') sel = soup.select('div.title a') #標題 u = soup.select('div.btn-group.btn-group-paging a') #a標籤 print ('本頁的URL為'+url) url = 'https://www.ptt.cc' + u[1]['href'] #上一頁的網址 for s in sel: #印出網址跟標題 print(s['href'], s.text)
- 範例:詳如「爬蟲_簡易說明.ipynb」之範例二
- 觀察下一頁按鈕的HTML標籤內容,發現上一頁按鈕的 a 標籤中有上一頁的網址為「/bbs/joke/index8140.html」
- 範例三:【PTT 八卦版】遇到按鈕
- 進入網站後會看到讓使用者點選「是否已滿18歲」按鈕
- 說明:
- Cookie:網站存放在瀏覽器的一小段內容
- 與伺服器互動:連線時,Cookie 放在 Request Headers 中送出
- 先開啟瀏覽器開發者模式(F12),並點選至network(網路),觀察點選「已滿18歲」後,會送給伺服器之封包內容,意即透過「檢視原始碼」→「Application」→「Cookies」觀察重要的 Cookie
- 範例:詳如「爬蟲_簡易說明.ipynb」之範例三
- 參考網頁
- 範例一 :【PTT 資訊版】爬取文章標題
- selenium
- 範例:模擬點擊
from selenium import webdriver driver = webdriver.Chrome() driver.get('http://www.google.com') # 更改網址以前往不同網頁
- 情境一:搜尋輸入
# 定位搜尋框 element = driver.find_element(by=By.CLASS_NAME, value='gLFyf.gsfi') # 傳入字串 element.send_keys('Selenium Python') # 點擊搜尋按鈕 button = driver.find_element(by=By.CLASS_NAME, value='gNO89b') # 點擊搜尋按鈕 button.click() # 反爬蟲:點擊搜尋按鈕 from selenium.webdriver.common.action_chains import ActionChains actions = ActionChains(element) actions.move_to_element(button).click(button) # 滑鼠先移到 button 上,然後再點擊 button actions.perform()
- 情境二:刪除輸入
# 定位搜尋框 element = driver.find_element(by=By.CLASS_NAME, value='gLFyf.gsfi') # 傳入字串 element.send_keys('Selenium Python') # 刪除原本已輸入的文字 element.clear()
- 滾動網頁捲軸
driver.execute_script('window.scrollTo(0, 500)') # 捲動到 500px 位置 sleep(1) h1 = driver.find_element_by_tag_name('h1') h3 = driver.find_element_by_tag_name('h3') script = ''' let h1 = arguments[0]; let h3 = arguments[1]; alert(h1, h3) ''' driver.execute_script(script, h1, h3) # 執行 JavaScript,印出元素 sleep(2) Alert(driver).accept() # 點擊提示視窗的確認按鈕,關閉提示視窗
- 瀏覽網頁的瀏覽紀錄
# 前往下一項 driver.forward() # 前往上一項 driver.back()
- 情境一:搜尋輸入
- 範例:模擬點擊
- Python 查詢
- 查詢設定:conda config --show
- 查詢 proxy
import urllib urllib.request.getproxies()
- 網路狀況
- Windows
- 檢視 IP Address
- 指令:ipconfig
- 結果:如果 IP Address 顯示為 0.0.0.0 或 169.x.x.x 則無法上網
- 測試網站是否活著
- 指令:ping 目的地網站名稱或IP Address
- 結果:如果出現 Request timed out. 就表示該網站和我們電腦間的網路連線無法建立
- 追蹤網路路徑
- 指令:tracert 目的地網站名稱或IP Address
- 測試網頁服務(HTTP)
- 指令:
- telnet 目的地網站名稱或IP Address 80
- telnet 目的地網站名稱或IP Address 443
- 指令:
- 檢視 IP Address
- Linux
- 測試網站是否活著
- 指令:ping 目的地網站名稱或IP Address
- 停止輸出:ctrl+c
- 追蹤網路路徑
- 指令:traceroute 目的地網站名稱或IP Address
- 測試網站是否活著
- Windows
- HTTP 狀態代碼
狀態代碼 說明 狀態代碼 說明 狀態代碼 說明 200 網頁正常 301 網頁搬家,重新導向到新的網址 400 錯誤的要求 401 未授權,需要憑證 403 沒有權限 404 找不到網頁 500 伺服器錯誤 503 伺服器暫時無法處理請求 (附載過大) 504 伺服器沒有回應
- 使用F12鍵查看Security
- 網站:https://www.ssllabs.com/ssltest/
- 網站:https://www.cdn77.com/tls-test