---
# System prepended metadata

title: 爬蟲3(selenium)
tags: [web crawler]

---

---
tags: web crawler
---

# 爬蟲3(selenium)

## selenium 是什麼
`selenium`是一個可以讓你的程式碼模擬真實操作 ex: 點擊、輸入文字、播放影片.....

十分的方便，基本上有了他你也不會想用`requests`了，那為什麼不先教他呢，<del>因為我不會</del>，因為`requests`可以讓你對網站的瀏覽有最基本的認識`get`, `post`, `put`, `delete`，當然，這只是極度基礎的部分，如果還想要深挖的話可能還有一堆協議`https`、`tcp`...，還有封包之類的東西(我也不會了 :poop: )。

總而言之，高中想做專案的話`selenium`就可以了，因為他也可以抓取網頁上的原始碼(html)，而且還可以更方便的進行登錄(基本上就是 跟你登陸的過程差不多( 點擊 -> 輸入密碼 -> 送出 ) , 基本上你在瀏覽器上手動作的他都可以做到。

## 準備工作 

基本上，如果你需要瀏覽網頁的話你需要一個瀏覽器 :poop:，那對於`selenium`來說，你就會需要[chrome driver](https://chromedriver.chromium.org/downloads)這個瀏覽器，當然你的電腦上要有chrome，然後版本要記得對上，不然會出事，
所以就可以把他下仔之後跟你的code放在同一個目錄之下。

之後在`terminal(cmd)`上安裝`selenium`就可以了 
```
在 cmd/terminal 內:
pip install selenium
```


## 初使化瀏覽器

最基礎的就這樣就可以了
```python=
from selenium import webdriver
driver = webdriver.Chrome()
```

當然，如果沒有遇到bug的話那你可能沒有寫過程式 :poop:

有時候可能遇到這種錯誤
```
USB: usb_device_handle_win.cc:1046 Failed to read descriptor from node connection: 
連結到系統的某個裝置失去作用。 (0x1F)
```

那這個時候就可以查一下，基本上就把錯誤複製貼上就好了 :poop:
那你就可以發現說他可能是因為某些東西然後出錯，耶會找到解決辦法。

```python=
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-logging'])
driver = webdriver.Chrome(options=options);
```
那就愉快的複製上去 :poop: 他就又能動了

## click 

那我們先來看一個最簡單的例子[pop cat](https://popcat.click/)，基本上用selenium一下子就會被封了，所以我們只是拿來當作練習（不要問我怎麼知道的 :poop: ) ，然後python十個線程跟一個線程差不多　:poop: 

:::spoiler 舊的寫法, 會抱錯
```python=
""" 初始化　driver"""
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-logging'])
driver = webdriver.Chrome(options=options);

""" 獲取網址　（有點像你在搜尋欄那邊直接打網址）　他還會幫你enter"""
driver.get("https://popcat.click/")
login = driver.find_element_by_class_name("title")
while 1==1 : # this is magic
    login.click() 就是點擊　
```
:::
```python=
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://popcat.click/")
login = driver.find_element(By.CLASS_NAME, "title")
while 1==1 : # this is magic
    login.click() 
```




## send key
基本上這個就是可以打字的東西，他可以幫你模擬鍵盤
```python=
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from time import sleep
driver = webdriver.Chrome()
driver.get("https://google.com/")

typing_blank = driver.find_element(By.XPATH, "/html/body/div[1]/div[3]/form/div[1]/div[1]/div[1]/div/div[2]/textarea")
typing_blank.send_keys("hello, world")
typing_blank.send_keys(Keys.RETURN)

sleep(5)
driver.quit();
driver.close()
```

至於XPATH如何或取，你只要到網頁原始碼（右鍵 -> 檢查）然後找到你要的區域再按一次又見，找到複製，就可以複製XPATH了，當然，它除了可以`By.XPATH`外，`id`, `class`也都是被允許的。

## login 

那現在就讓我們來進行合併的練習吧。

`./data.json`
```jsonld=
{
	"contestid": [229, 226],
	"url" :{
		"login": "https://dandanjudge.fdhs.tyc.edu.tw/Login",
		"Ranking" : "https://dandanjudge.fdhs.tyc.edu.tw/ContestRanking",
		"Edit": "https://dandanjudge.fdhs.tyc.edu.tw//EditContestants"	

	},
	"TimeLimit": 3 
}
```


```python=
BaseDataFileFatherName = "Test_1"
DataFilePos = "./data.json"
Cookie = list() 

def WriteData( filepos, Data ) :
    print( f"Ouptut Data into file {filepos}..." );
    with open( filepos, 'w', encoding="utf-8" ) as f : 
        f.write( Data  );
        
def readJson ( filepos  ) :
    with open( filepos  ) as f :
        data =json.loads( f.read() );
    return data;
        
UnitData = readJson( DataFilePos  );


def Login(driver) :
    """login"""

    driver.get( UnitData['url'][ 'login' ] );

    """ 如果有cookie存下來的話，在完整的code的時候可以把它刪掉"""
    try: 
        lgcookie = readJson( f'./{BaseDataFileFatherName}/cookie.json' );
        for c in lgcookie :
            driver.add_cookie( {'name':c['name'], 'value':c['value']} );
    except:
        print("No Cookie Now")

    driver.refresh();
    if driver.current_url == "https://dandanjudge.fdhs.tyc.edu.tw/" :
        Cookie = driver.get_cookies()
        print(Cookie);
        WriteData(f'./{BaseDataFileFatherName}/cookie.json', json.dumps(Cookie, indent=4, ensure_ascii=False));
        return "Login Sucess"
    
    """ 輸入帳號"""
    AccountName = input("Your account:");
    """ 找到帳號框( blank )"""
    AccountEle = driver.find_element(By.CSS_SELECTOR ,'div.col-md-4:nth-child(2) > form:nth-child(1) > div:nth-child(1) > div:nth-child(2) > input:nth-child(2)'  ) ;
    """ 輸入帳號框( blank )"""
    AccountEle.send_keys( AccountName );

    """ 輸入密碼 """
    PassWordName = input("your password:")
    """ 找到密碼框( blank )"""
    PasswordEle = driver.find_element( By.XPATH, '//*[@id="passwd"]' );
    """ 輸入密碼框( blank )"""
    PasswordEle.send_keys( PassWordName )

    """ 找到登入按鈕 """
    driver.find_element( By.XPATH,'/html/body/div[4]/div[2]/div[2]/form/button[1]' ).click();

    sleep(5)
    """ 這邊是觀察到如果有成功登陸的話就可以發現它會自動導回到首頁 """
    if driver.current_url == "https://dandanjudge.fdhs.tyc.edu.tw/" :
        Cookie = driver.get_cookies()
        print(Cookie);
        WriteData(f'./{BaseDataFileFatherName}/cookie.json', json.dumps(Cookie, indent=4, ensure_ascii=False));
        print("Login Sucess")
        return "Login Sucess"
    else :
        print( "Login Fail" )
        return "Login Fail"
    
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-logging'])
driver = webdriver.Chrome(options=options);
Login(driver)
```

## 取代 selenium 

`driver.page_source`就可以拿到網頁的原碼了，所以就可以用`BeautifulSoup`處理，

## 成果 
[我的code](https://github.com/william1010121/DDJ-contest-score/tree/WindowCode)