Web 접속 방법 Rust, Python 비교

러스트의 경우 처음에 명령 프롬프트 창에서 포트를 열어놓고 Cargo run을 하라고 하여 Python은 포트를 열 필요없이 잘 접속되는데 해서 비교하게 되었습니다. 그리고, 보면 파이썬은 편리한 상태를 만들어 놓았는데, Rust는 처음부터 내가 만들어가야 하는 상황입니다.

1. Rust를 이용한 웹 접속

가. 명령 프롬프트 방식

(1) 명령 프롬프트에서 프트 열기

chromedriver –port=9515를 실행해서 Chromedriver를 실행시킵니다.

명령 프롬프트에서 9515 포트 열기

Chromedriver가 Path에 있다면 그냥 실행하면 되는데, path가 설정되어 있지 않아, chromedriver.exe가 있는 폴더로 이동해서 실행했습니다.

(2) 브라우저 열기 Rust 코드

(가) Cargo.toml
[dependencies]
thirtyfour = "0.36.1"
tokio = { version = "1", features = ["full"] }

thirtyfour와 tokio 라이브러리를 가져와야 합니다.

(나) main.rs
use thirtyfour::prelude::*;
use tokio;

#[tokio::main]
async fn main() -> WebDriverResult<()> {
    // 이미 chromedriver가 9515 포트에서 실행 중이라고 가정
    let driver = WebDriver::new("http://localhost:9515", DesiredCapabilities::chrome()).await?;

    // 페이지 접속
    driver.get("https://www.rust-lang.org").await?;

    // 타이틀 가져오기
    let title = driver.title().await?;
    println!("Page title: {}", title);

    // 종료
    driver.quit().await?;
    Ok(())
}

코드이 내용은 port가 열려 있기 때문에 다시 열 필요는 없고, 9515 포트로 driver를 설정한 다음, rust-lang.org에 접속한 후 title을 가져와서 화면에 출력하는 것입니다.

문제 없이 코드가 실행되고, title이 표시됩니다.

cargo run을 이용해 rust-lang-org에 접속한 후 타이틀을 가져와 화면에 출력

나. 코드로 포트 열기 방식

명령 프롬프트에서 포트를 연 다음 Cargo run을 한다는 것이 이상하므로 Rust에서 포트를 열고, 실행하려면 아래와 같이 코드를 작성하면 됩니다.

Cargo.toml은 동일하고,

main.rs만 아래와 같이 수정하면 됩니다.

use std::process::Command;
use thirtyfour::prelude::*;
use tokio;

#[tokio::main]
async fn main() -> WebDriverResult<()> {
    // 실행파일이 있는 디렉토리 경로
    let exe_dir = std::env::current_exe()
        .unwrap()
        .parent()
        .unwrap()
        .to_path_buf();
    let chromedriver_path = exe_dir.join("chromedriver.exe");
    println!("chromedriver 경로: {}", chromedriver_path.display());

    // chromedriver 실행
    let mut child = Command::new(&chromedriver_path)
        .arg("--port=9515")
        .spawn()
        .expect("chromedriver 실행 실패");

    // WebDriver 클라이언트 연결
    let caps = DesiredCapabilities::chrome();
    let driver = WebDriver::new("http://localhost:9515", caps).await?;

    driver.get("https://www.rust-lang.org").await?;
    println!("현재 페이지 타이틀: {}", driver.title().await?);

    // 브라우저 닫기
    driver.quit().await?;
    // chromedriver 프로세스 종료
    child.kill().ok();

    Ok(())
}

use std::process::Command;가 추가되었습니다.

main에서 먼저 chromedriver_path를 설정하고,

Command::new를 이용해 포트를 연 다음 child에 저장하고,

caps는 python Selenium에서 사용하는 ChromeOptions 역할입니다. 기본적인 옵션만 설정하는 것입니다. caps.add_arg(“–headless”)?; 등을 추가해서 옵션을 추가할 수 있습니다.

그리고, WebDriver::new로 http://localhost:9515라고 9515포트를 이용해 localhost를 연 다음

driver.get로 https://www.rust-lang.org를 연 다음

driver.title().await?로 title을 가져와서 화면에 출력합니다.

아래는 Visual Studio Code에서 Run한 장면입니다.

Compile과 실행 잘 되고, ChromeDriver was started successfully on port 9515.와

현재 페이지 타이틀 : Rust Programming Language라고 잘 나옵니다.

9515 포트 열기와 rust-lang.org에 접속해서 title 가져오기를 통합한 실행 화면

2. Python을 이용한 웹 접속

가. chrome_connect.py

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import os

def main():
    # 실행 파일이 있는 디렉토리 기준으로 chromedriver.exe 찾기
    exe_dir = os.path.dirname(os.path.abspath(__file__))
    chromedriver_path = os.path.join(exe_dir, "chromedriver.exe")

    # chromedriver.exe 고정 경로
    # chromedriver_path = r"C:\android\chromedriver.exe"
    # print(f"chromedriver 경로: {chromedriver_path}")

    # chromedriver 실행 (포트 지정 없이 내부적으로 관리)
    service = Service(chromedriver_path)
    options = webdriver.ChromeOptions()

    driver = webdriver.Chrome(service=service, options=options)

    try:
        driver.get("https://www.rust-lang.org")
        print(f"현재 페이지 타이틀: {driver.title}")
    finally:
        driver.quit()

if __name__ == "__main__":
    main()

Python은 Cargo.toml과 같은 설정이 필수가 아니고,

바로 python code를 위와 같이 작성하면 됩니다.

실행 결과는 아래와 같습니다.

파이썬으로 chromedriver를 실행한 후 rust-lang.org의 타이틀을 화면에 출력

나. 코드 내용

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import os

필요한 selenium과 os 라이브러리를 불러옵니다.

    # 실행 파일이 있는 디렉토리 기준으로 chromedriver.exe 찾기
    exe_dir = os.path.dirname(os.path.abspath(__file__))
    chromedriver_path = os.path.join(exe_dir, "chromedriver.exe")

    # chromedriver.exe 고정 경로
    # chromedriver_path = r"C:\android\chromedriver.exe"


실행 파일이 있는 폴더의 chromedriver.exe를 chromedriver_path로 설정합니다.

주석 처리한 것처럼 고정 경로로 지정할 수도 있습니다. 여러 프로그램에서 공통적으로 사용할 수 있으므로 PC에서만 작업한다면 이것이 편할 수 있습니다.

print(f"chromedriver 경로: {chromedriver_path}")

chromedriver_path를 화면에 출력합니다.

    # chromedriver 실행 (포트 지정 없이 내부적으로 관리)
service = Service(chromedriver_path)
options = webdriver.ChromeOptions()

Service 메소드를 이용해 service를 생성하고, webdriver.ChromeOptions()로 크롬 설정을 기본으로 합니다.

driver = webdriver.Chrome(service=service, options=options)

service와 options 설정으로 크롬을 열고, driver 객체에 담습니다.

    try:
driver.get("https://www.rust-lang.org")
print(f"현재 페이지 타이틀: {driver.title}")
finally:
driver.quit()

www.rust-lang.org 열기를 시도해서 성공하면 페이지의 타이틀을 driver.title로 가져와서 화면에 표시합니다.

그리고, 크롬을 종료합니다.

3. 러스트와 파이썬 비교

Rust는 Port를 반드시 지정해야 하는데, Python은 selenium을 이용하기 때문에 포트를 지정할 필요가 없는 차이점이 있습니다.

자세히 말하면 Rust의 thirtyfour는 W3C WebDriver 프로토콜을 따르는 라이브러리라서, chromedriver.exe를 서버처럼 띄우고 http://localhost:9515 같은 포트를 통한 HTTP 요청으로 제어하는데 비해

Python의 selenium은 내부적으로 chromedriver.exe를 subprocess로 실행하고, 외부에서 포트 번호를 직접 지정할 필요 없이 Selenium이 알아서 관리합니다.

4. 실행 파일 사이즈

pyinstaller -F -w chrome_connect.py로 실행한 후 파일 사이즈를 보면

18메가 정도되는데,

cargo run으로 생성한 실행 파일 크기는 8메가 정도되는데,

cargo build –release해서 만든 Rust 실행 파일을 보면 4메가 정도로 파이썬 18메가의 22%뿐이 안됩니다.

속도도 미세하지만 Rust가 빠른 듯 합니다.

Rust 까다롭고, 생소한 측면이 너무 많지만 좋기때문에 자꾸 익히고 적응해나가야 하겠습니다.