iT邦幫忙

1

Python爬蟲,真的很簡單

zyx 2021-12-03 11:49:341107 瀏覽

https://ithelp.ithome.com.tw/upload/images/20211203/20144476VdKRTCOUsq.png

首先要先了解什麼是爬蟲:
網路爬蟲可理解成,可自動蒐集網頁上資訊的程式。本篇會介紹靜態與動態網頁的爬蟲作法,至於兩場的使用場合,理論上來說動態的相對比較不會有問題

本篇爬蟲皆使用python執行,所以執行前請先確認電腦有可執行python程式的環境,可參考以下連結
安裝python請點我

靜態網頁爬蟲

靜態網頁爬蟲方法 (BeautifulSoup)

import psycopg2 # pip3 install psycopg2
import urllib.request # pip3 install requests
from bs4 import BeautifulSoup  # pip3 install psycopg2

HOST = "localhost"
PORT = 5432
USER = "liyanxian"
PASSWD = ''
DATABASE = "postgres"
try:
    conn = psycopg2.connect(host=HOST, port=PORT, user=USER,password=PASSWD,
                            database=DATABASE)
    curr = conn.cursor()
    print('開始連接資料庫')
except:
    print('資料庫連接失敗')
    raise

url = "http://www.smeacommercialdistrict.tw/location/street"
# 發一個request去這串網址 並且拿回結果
response = urllib.request.urlopen(url)
data = response.read()
text = data.decode('utf-8-sig')

# 這邊參數很多可以選擇 不過基本上都在做同一件事情 (不過現在一般都推薦lxml 因為效能好)
soup = BeautifulSoup(text, "lxml")  # parse  (要先pip install lxml 不然會噴錯)

html_div = soup.find('div',class_="col-12")  #找到我們需要蒐集資料的外框 (find只會找第一個)

# 去外框裡面找到每一個(find_all)城市名稱
city_name = html_div.find_all(
    'h3', attrs={'class': 'county_title'})

#去外框裡面找到每一個(find_all)表格
table_content = html_div.find_all(
    'table', attrs={'class': 'table table-striped table-bordered table-sm contactus_table'})

# range(len(xxx)) vs enumerate(xxx) 前者不可傳val 後者可傳 
for index in range(len(city_name)):
    # 找出表格裡所有的tr (select跟find_all功能其實一樣 只是語法不太一樣)
    table_tbody_tr = table_content[index].select(
        'tbody > tr')
    # 這邊在做資料庫的Insert 
    for index2, val2 in enumerate(table_tbody_tr):
        curr.execute("""INSERT IGNORE INTO `bussinessdistrict` 
			(`id`, `city`, `businessname`,`regio`, `businessarea`)
			 VALUES (%s,%s,%s,%s,%s)""",
                     (table_tbody_tr[index2].contents[1].contents[0], city_name[index].contents[0], table_tbody_tr[index2].contents[3].contents[0], table_tbody_tr[index2].contents[5].contents[0], table_tbody_tr[index2].contents[7].contents[0]))
        conn.commit()  # 確認送出(必要)
curr.close()        
conn.close()

動態網頁爬蟲

為何需要動態網頁爬蟲?

因為在呼叫動態網頁時,無法取得該網頁與呼叫後端的“資料”。此外,也有SPA網頁只有讀到空白html的可能性(例如:中油網站)
在動態爬蟲我們需要chrome的driver來幫我們執行瀏覽器可至以下連結下載
https://chromedriver.chromium.org/downloads

認識xPath

xPath是一種用來尋找XML文件中某個節點(node)位置的查詢語。
實作:以我司的登入系統為例
https://ithelp.ithome.com.tw/upload/images/20211203/20144476ly8ZhXEVgb.png

XPath vs. full XPath
"//*[@id="root"]/div[3]/div/form/div[2]/div/input" vs. "/html/body/div/div[3]/div/form/div[2]/div/input"

Step.1:抓取NIS的帳號輸入方塊xpath://*[@id="root"]/div[3]/div/form/div[2]/div/input

Step.2 定位帳號輸入框

Step.3 傳入字串

Step.4:抓取NIS的密碼輸入方塊xpath

Step.5 定位密碼框

Step.6 傳入字串

Step.7:抓取NIS的登入方塊xpath

Step.8 定位登入按鈕

Step.9 點擊登入按鈕

輸入完帳號密碼後 就可以透過button點擊登入按鈕

因諸多考量,不公開底下python語言中的url及帳號密碼

動態爬蟲方法 (Selenium)

from selenium import webdriver


options = webdriver.ChromeOptions()
options.add_argument('--headless')  # 背景執行設定
driver = webdriver.Chrome(executable_path='./chromedriver' ) # chromedriver的路徑(檔名要記得確認)
# driver = webdriver.Chrome(executable_path='./chromedriver', chrome_options=options)

url = 'jubo_url' # 進入點的網址
driver.get(url)
driver.implicitly_wait(10)  # 如果在規定時間內網頁加載完成,則執行下一步,否則一直等到時間終止


account = driver.find_element_by_xpath('/html/body/div/div[3]/div/form/div[2]/div/input')  
account.send_keys("xxxxxxxxxxxx") # 輸入帳號

password =  driver.find_element_by_xpath('/html/body/div/div[3]/div/form/div[3]/div/input')  
password.send_keys("xxxxxxxxxxxx") #輸入密碼
button = driver.find_element_by_xpath('/html/body/div/div[3]/div/form/button')
button.click()

結語

爬蟲看起來很萬能可以長期抓取想要的資料,但面對常改版或出事的網頁時,爬蟲常會遇到程式"執行有誤"的問題發生,雖可透過發訊息告知使用者,不過收到訊息後大概表示又要修改爬蟲程式,實際上頻繁的改動也是相當耗神。


尚未有邦友留言

立即登入留言