Try   HackMD

2022-12-18 第六天 Python網路爬蟲應用實務班上課記錄

tags: python 爬蟲 crawler

Selenium

from selenium import webdriver # 初始化WebDriver driver = webdriver.Chrome('./chromedriver') # 等待瀏覽器下載網頁的時間(如果瀏覽器提早下載完網頁就會馬上結束等待) driver.implicitly_wait(10) # 連線到網站 driver.get('https://rate.bot.com.tw/xrt?Lang=zh-TW') # 取得網站的標題 print('網頁標題:', driver.title) # 取得網頁內容 html = driver.page_source print('網頁內容', html) # 關閉selenium(瀏覽器會被關閉)以節省記憶體 driver.quit()

改用selenium來爬取台灣銀行網頁

from selenium import webdriver from bs4 import BeautifulSoup import time import csv # 初始化WebDriver driver = webdriver.Chrome('./chromedriver') # 等待瀏覽器下載網頁的時間(如果瀏覽器提早下載完網頁就會馬上結束等待) driver.implicitly_wait(10) # 連線到網站 driver.get('https://rate.bot.com.tw/xrt?Lang=zh-TW') # 取得網站的標題 print('網頁標題:', driver.title) # 取得網頁內容 html_doc = driver.page_source print('網頁內容', html_doc) # 關閉selenium(瀏覽器會被關閉)以節省記憶體 driver.quit() #-------------------------------- 以下完全一樣 soup = BeautifulSoup(html_doc, 'html.parser') # print(soup.prettify()) # 格式化下載後的網頁 tbody = soup.find('tbody') all_rates_rows = tbody.find_all('tr') all_rate_data = [] for row in all_rates_rows: # 存放匯率資訊 rate_data = [] # 取得幣別 money_type = row.select_one('.hidden-phone.print_show').string.strip() rate_data.append(money_type) # 取得匯率資訊 rate_data.append(row.select_one('td[data-table="本行現金買入"].print_width').string.strip()) rate_data.append(row.select_one('td[data-table="本行現金賣出"].print_width').string.strip()) rate_data.append(row.select_one('td[data-table="本行即期買入"].print_width').string.strip()) rate_data.append(row.select_one('td[data-table="本行即期賣出"].print_width').string.strip()) all_rate_data.append(rate_data) # 全部資料 print(all_rate_data) # 以目前時間產生檔名 now = time.localtime() file_name = time.strftime('%Y%m%d_%H%M%S.csv', now) print('輸出的檔案名稱:', file_name) with open(file_name, 'w', encoding='utf-8', newline='') as csvfile: csvfile.write('\ufeff') # UTF-8 BOM writer = csv.writer(csvfile) # 建立CSV寫入器 writer.writerow(['幣別', '現金買入', '現金賣出', '即期買入', '即期賣出']) writer.writerows(all_rate_data)

下載台灣銀行匯率檔案

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from bs4 import BeautifulSoup import time import csv # 初始化WebDriver driver = webdriver.Chrome('./chromedriver') # 等待瀏覽器下載網頁的時間(如果瀏覽器提早下載完網頁就會馬上結束等待) driver.implicitly_wait(10) # 連線到網站 driver.get('https://rate.bot.com.tw/xrt?Lang=zh-TW') # 取得網站的標題 print('網頁標題:', driver.title) # 取得網頁內容 html_doc = driver.page_source print('網頁內容', html_doc) # 暫停2秒 time.sleep(2) try: # 以超連結文字定位下載CSV按鈕,並將回傳的按鈕存到download_csv變數內 download_csv = driver.find_element(By.LINK_TEXT, '下載 Excel (CSV)檔') # 取得標籤名稱 print('tag name=', download_csv.tag_name) # 取得href屬性值 print('href=', download_csv.get_attribute('href')) # 點擊該元素(標籤) download_csv.click() except NoSuchElementException: print('無法定位下載按鈕') # 關閉selenium(瀏覽器會被關閉)以節省記憶體 driver.quit()

執行JavaScript

# 執行JavaScript程式碼(該程式碼不需要存在網站上) driver.execute_script('document.getElementById("h1_small_id").innerHTML = "Hello"') time.sleep(2) driver.execute_script('document.getElementById("h1_small_id").innerHTML = "Python"') time.sleep(2) driver.execute_script('document.getElementById("h1_small_id").innerHTML = "你好"') # driver.execute_script('alert("網站已關閉")')

登入台北通網站

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from bs4 import BeautifulSoup import time import csv # 初始化WebDriver driver = webdriver.Chrome('./chromedriver') # 等待瀏覽器下載網頁的時間(如果瀏覽器提早下載完網頁就會馬上結束等待) driver.implicitly_wait(10) # 連線到網站 driver.get('https://id.taipei/tpcd/login') # 取得網站的標題 print('網頁標題:', driver.title) # 取得網頁內容 html_doc = driver.page_source print('網頁內容', html_doc) # 暫停5秒 time.sleep(5) try: # 定位帳號輸入框 account = driver.find_element(By.ID, 'account') # 輸入帳號 account.send_keys('aaron') time.sleep(2) # 定位密碼輸入框 password = driver.find_element(By.ID, 'pass') # 輸入密碼 password.send_keys('12345678') time.sleep(2) # 定位登入按鈕 login = driver.find_element(By.CSS_SELECTOR, '.green_btn.login_btn') # 點擊登入按鈕 login.click() time.sleep(5) except NoSuchElementException: print('無法定位下載按鈕') # 關閉selenium(瀏覽器會被關閉)以節省記憶體 driver.quit()

假設登入按鈕的位置不固定

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from bs4 import BeautifulSoup import time import csv # 初始化WebDriver driver = webdriver.Chrome('./chromedriver') # 等待瀏覽器下載網頁的時間(如果瀏覽器提早下載完網頁就會馬上結束等待) driver.implicitly_wait(10) # 連線到網站 driver.get('https://id.taipei/tpcd/login') # 取得網站的標題 print('網頁標題:', driver.title) # 取得網頁內容 html_doc = driver.page_source # print('網頁內容', html_doc) # 暫停5秒 time.sleep(5) try: # 定位帳號輸入框 account = driver.find_element(By.ID, 'account') # 輸入帳號 account.send_keys('aaron') # time.sleep(2) # 定位密碼輸入框 password = driver.find_element(By.ID, 'pass') # 輸入密碼 password.send_keys('12345678') time.sleep(2) # 定位登入按鈕 login = driver.find_elements(By.CSS_SELECTOR, 'a[href][class="green_btn login_btn"]') for c in login: if c.get_attribute('innerText') == '登入': # 點擊登入按鈕 c.click() time.sleep(5) except NoSuchElementException: print('無法定位下載按鈕') # 關閉selenium(瀏覽器會被關閉)以節省記憶體 driver.quit()

實戰

透過Selenium做Google搜尋並爬回結果

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.keys import Keys import time driver = webdriver.Chrome('./chromedriver') driver.implicitly_wait(10) driver.get('https://www.google.com') # 連線到Google搜尋網站 print(driver.title) try: # 定位搜尋輸入框 search_input = driver.find_element(By.NAME, 'q') # 送出搜尋文字 search_input.send_keys('aaronlife') time.sleep(1) # 送出ENTER按鍵 search_input.send_keys(Keys.ENTER) time.sleep(1) # driver內容就是當前的頁面,不管網頁跳到哪裡去 subjects = driver.find_elements(By.CLASS_NAME, 'LC20lb') # 搜尋結果標題 links = driver.find_elements(By.CLASS_NAME, 'yuRUbf') # 搜尋結果連結 all = zip(subjects, links) for item in all: addr = item[1].find_element(By.TAG_NAME, 'a').get_attribute('href') print(f'{item[0].text} [{addr}]') except NoSuchElementException: print('定位失敗') driver.quit()

一併蒐集分頁的搜尋結果

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.keys import Keys import time driver = webdriver.Chrome('./chromedriver') driver.implicitly_wait(10) driver.get('https://www.google.com') # 連線到Google搜尋網站 print(driver.title) try: # 定位搜尋輸入框 search_input = driver.find_element(By.NAME, 'q') # 送出搜尋文字 search_input.send_keys('aaron') time.sleep(1) # 送出ENTER按鍵 search_input.send_keys(Keys.ENTER) time.sleep(1) # driver內容就是當前的頁面,不管網頁跳到哪裡去 # 解析搜尋結果 subjects = driver.find_elements(By.CLASS_NAME, 'LC20lb') # 搜尋結果標題 links = driver.find_elements(By.CLASS_NAME, 'yuRUbf') # 搜尋結果連結 all = zip(subjects, links) for item in all: addr = item[1].find_element(By.TAG_NAME, 'a').get_attribute('href') print(f'{item[0].text} [{addr}]') # 練習: 將搜尋結果的前五頁都爬出來 for page_num in range(2, 6): print('Page', page_num) # 定位每一頁的分頁超連結 page = driver.find_element(By.CSS_SELECTOR, 'a[aria-label="Page ' + str(page_num) + '"]') # 點擊分頁超連結 page.click() # 解析搜尋結果 subjects = driver.find_elements(By.CLASS_NAME, 'LC20lb') # 搜尋結果標題 links = driver.find_elements(By.CLASS_NAME, 'yuRUbf') # 搜尋結果連結 all = zip(subjects, links) for item in all: addr = item[1].find_element(By.TAG_NAME, 'a').get_attribute('href') print(f'{item[0].text} [{addr}]') time.sleep(1) except NoSuchElementException: print('定位失敗') driver.quit()

爬出相關搜尋

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.keys import Keys import time driver = webdriver.Chrome('./chromedriver') driver.implicitly_wait(10) driver.get('https://www.google.com') # 連線到Google搜尋網站 print(driver.title) try: # 定位搜尋輸入框 search_input = driver.find_element(By.NAME, 'q') # 送出搜尋文字 search_input.send_keys('aaron') time.sleep(1) # 送出ENTER按鍵 search_input.send_keys(Keys.ENTER) time.sleep(1) # driver內容就是當前的頁面,不管網頁跳到哪裡去 # 相關搜尋 print('相關搜尋:') related = driver.find_elements(By.CLASS_NAME, 's75CSd') # 相關搜尋 for re in related: print(re.find_element(By.TAG_NAME, 'b').text) # 解析搜尋結果 subjects = driver.find_elements(By.CLASS_NAME, 'LC20lb') # 搜尋結果標題 links = driver.find_elements(By.CLASS_NAME, 'yuRUbf') # 搜尋結果連結 all = zip(subjects, links) for item in all: addr = item[1].find_element(By.TAG_NAME, 'a').get_attribute('href') print(f'{item[0].text} [{addr}]') # 練習: 將搜尋結果的前五頁都爬出來 for page_num in range(2, 6): print('Page', page_num) # 定位每一頁的分頁超連結 page = driver.find_element(By.CSS_SELECTOR, 'a[aria-label="Page ' + str(page_num) + '"]') # 點擊分頁超連結 page.click() # 解析搜尋結果 subjects = driver.find_elements(By.CLASS_NAME, 'LC20lb') # 搜尋結果標題 links = driver.find_elements(By.CLASS_NAME, 'yuRUbf') # 搜尋結果連結 # 相關搜尋 print('相關搜尋:') related = driver.find_elements(By.CLASS_NAME, 's75CSd') # 相關搜尋 for re in related: print(re.find_element(By.TAG_NAME, 'b').text) all = zip(subjects, links) for item in all: addr = item[1].find_element(By.TAG_NAME, 'a').get_attribute('href') print(f'{item[0].text} [{addr}]') # time.sleep(1) except NoSuchElementException: print('定位失敗') driver.quit()

資料定位的三種方式

  1. 土法煉鋼:在瀏覽器點右鍵,檢視原始碼後直接用網頁內容來搜尋資料被什麼元素包住。
  2. 先排版:有些網站原始碼較混亂,可以使用網路上的HTML排版工具先排版後再進行資料定位。
  3. 使用Chrome的開發工具,在想要定位的元素上點滑鼠右鍵->檢查(Inspect)