Sử dụng Selenium để Tự động hóa Trình duyệt và Thu thập Dữ liệu Web

Selenium là một công cụ mạnh mẽ cho phép bạn tự động hóa các tương tác với trình duyệt web, làm cho nó trở thành một lựa chọn lý tưởng cho việc thu thập dữ liệu web (web scraping). Bài viết này sẽ hướng dẫn bạn cách cài đặt, sử dụng các chức năng cơ bản và thực hiện các ví dụ thu thập dữ liệu thực tế bằng Selenium.

I. Cài đặt và Sử dụng Cơ bản

1.1. Cài đặt

Để Selenium tương tác với trình duyệt, bạn cần tải về trình điều khiển (webdriver) tương ứng với trình duyệt bạn muốn sử dụng:

  • Chrome: Tải ChromeDriver từ đây hoặc đây.
  • Firefox: Tải GeckoDriver từ đây.

Lưu ý: Đảm bảo độ phân giải màn hình của bạn được đặt thành 100% để tránh các lỗi không mong muốn.

1.2. Định vị Phần tử (Element Locators)

Selenium cung cấp nhiều phương thức để xác định vị trí các phần tử trên trang web. Dưới đây là các phương thức phổ biến:

Định vị một phần tử Định vị nhiều phần tử Ý nghĩa
find_element_by_id find_elements_by_id Định vị qua thuộc tính id.
find_element_by_name find_elements_by_name Định vị qua thuộc tính name.
find_element_by_xpath find_elements_by_xpath Định vị bằng biểu thức XPath.
find_element_by_link_text find_elements_by_link_text Định vị qua văn bản của liên kết () một cách chính xác.
find_element_by_partial_link_text find_elements_by_partial_link_text Định vị qua một phần văn bản của liên kết.
find_element_by_tag_name find_elements_by_tag_name Định vị qua tên thẻ (tag name).
find_element_by_class_name find_elements_by_class_name Định vị qua tên lớp (class name).
find_element_by_css_selector find_elements_by_css_selector Định vị bằng bộ chọn CSS (CSS selector).

Ví dụ:

<html>
  <head>
  <body link="#0000cc">
    <a id="result_logo" href="/" onmousedown="return c({'fm':'tab','tab':'logo'})">
    <form id="form" class="fm" name="f" action="/s">
      <span class="soutu-btn"></span>
        <input id="kw" class="s_ipt" name="wd" value="" maxlength="255" autocomplete="off">
# Định vị phần tử
driver.find_element("id", "kw")
driver.find_element("name", "wd")
driver.find_element("class name", "s_ipt")
driver.find_element("tag name", "input")

# Sử dụng XPath
driver.find_element("xpath", "//input[@id='kw']")
driver.find_element("xpath", "//input[@name='wd']")
driver.find_element("xpath", "//input[@class='s_ipt']")
driver.find_element("xpath", "/html/body/form/span/input")
driver.find_element("xpath", "//span[@class='soutu-btn']/input")
driver.find_element("xpath", "//form[@id='form']/span/input")
driver.find_element("xpath", "//input[@id='kw' and @name='wd']")

1.3. Các Phương thức Điều khiển Trình duyệt Phổ biến

Thư viện selenium.webdriver cung cấp các phương thức để điều khiển trình duyệt:

from selenium import webdriver
from time import sleep

# Khởi tạo trình duyệt (ví dụ: Firefox)
# Thay thế bằng đường dẫn thực tế đến geckodriver của bạn
driver = webdriver.Firefox(executable_path="path/to/geckodriver")
driver.get("https://www.baidu.com/")

# 1. Thay đổi kích thước cửa sổ trình duyệt
driver.set_window_size(1024, 768)

# 2. Quay lại trang trước
driver.back()

# 3. Chuyển tới trang tiếp theo
driver.forward()

# 4. Tải lại trang hiện tại
driver.refresh()

# 5. Xóa nội dung trong một trường nhập liệu
element.clear() # Giả sử 'element' là một phần tử input

# 6. Nhập văn bản vào một phần tử
element.send_keys("Nội dung cần nhập") # Giả sử 'element' là một phần tử input

# 7. Nhấp vào một phần tử
element.click() # Giả sử 'element' là một phần tử có thể nhấp

# 8. Gửi biểu mẫu (submit form)
element.submit() # Giả sử 'element' là một phần tử trong biểu mẫu

# 9. Lấy giá trị thuộc tính của phần tử
attribute_value = element.get_attribute("attribute_name")

# 10. Kiểm tra xem phần tử có hiển thị hay không
is_visible = element.is_displayed()

# 11. Lấy kích thước của phần tử
element_size = element.size # Trả về một dictionary {'width': w, 'height': h}

# 12. Lấy văn bản hiển thị của phần tử
element_text = element.text

# 13. Đóng tất cả các tab và thoát trình duyệt
driver.quit()

# 14. Đóng tab hiện tại
driver.close()

1.4. Thao tác với Bàn phím

Sử dụng Keys để mô phỏng các phím bấm trên bàn phím:

Mô phỏng phím bấm Mô tả
send_keys(Keys.BACK_SPACE) Phím Backspace
send_keys(Keys.SPACE) Phím Space
send_keys(Keys.TAB) Phím Tab
send_keys(Keys.ESCAPE) Phím Esc
send_keys(Keys.ENTER) Phím Enter

Sử dụng tổ hợp phím:

Mô phỏng tổ hợp phím Mô tả
send_keys(Keys.CONTROL, 'a') Chọn tất cả (Ctrl + A)
send_keys(Keys.CONTROL, 'c') Sao chép (Ctrl + C)
send_keys(Keys.CONTROL, 'x') Cắt (Ctrl + X)
send_keys(Keys.CONTROL, 'v') Dán (Ctrl + V)
send_keys(Keys.F1) ... send_keys(Keys.F12) Các phím chức năng F1 đến F12

1.5. Thao tác với Hộp Chọn (Dropdown)

Thư viện selenium.webdriver.support.select cung cấp lớp Select để xử lý các phần tử <select>:

Phương thức Mô tả
select_by_value("gia_tri") Chọn dựa trên thuộc tính value của tùy chọn.
select_by_index(index) Chọn dựa trên chỉ số (index) của tùy chọn (bắt đầu từ 0).
select_by_visible_text("van_ban") Chọn dựa trên văn bản hiển thị của tùy chọn.

Ví dụ:

from selenium import webdriver
from selenium.webdriver.support.ui import Select
from time import sleep

# Thay thế bằng đường dẫn thực tế đến chromedriver của bạn
driver = webdriver.Chrome("path/to/chromedriver")
driver.implicitly_wait(10) # Chờ tối đa 10 giây để tìm phần tử
driver.get('https://www.baidu.com') # Thay bằng URL có hộp chọn thực tế

# Ví dụ giả định: Tương tác với hộp chọn cài đặt tìm kiếm
# (URL và cấu trúc HTML có thể thay đổi)
try:
    # 1. Di chuột đến liên kết "设置" (Cài đặt) và nhấp
    driver.find_element("link text", "设置").click()
    sleep(1)
    # 2. Mở "搜索设置" (Cài đặt tìm kiếm)
    driver.find_element("link text", "搜索设置").click()
    sleep(2)

    # 3. Chọn số lượng kết quả hiển thị
    # Định vị phần tử <select>
    select_element = driver.find_element("xpath", "//select[@id='nr']")
    # Sử dụng lớp Select để thao tác
    select_object = Select(select_element)
    select_object.select_by_value('50')  # Chọn hiển thị 50 kết quả

    sleep(3)
finally:
    driver.quit()

II. Ví dụ Thu thập Dữ liệu Web

Ví dụ 1: Thu thập dữ liệu từ trang có phân trang

Ví dụ này minh họa cách thu thập dữ liệu từ nhiều trang của một trang web có chức năng phân trang.

from lxml import etree
from selenium import webdriver
import time

# Thay thế bằng đường dẫn thực tế đến chromedriver của bạn
driver = webdriver.Chrome("path/to/chromedriver")
url = 'http://example.com/data' # Thay bằng URL thực tế
driver.get(url)

# Thu thập dữ liệu từ 3 trang đầu tiên
time.sleep(2) # Đợi trang tải xong

# Lấy mã HTML của trang hiện tại
page_source = driver.page_source
all_pages_html = [page_source]

# Lặp qua các trang tiếp theo
for _ in range(2): # Lặp 2 lần nữa để có tổng cộng 3 trang
    try:
        # Định vị và nhấp vào nút "Trang tiếp theo"
        next_page_button = driver.find_element("xpath", '//*[@id="pageIto_next"]') # Thay đổi XPath nếu cần
        next_page_button.click()
        time.sleep(1) # Đợi trang mới tải xong
        all_pages_html.append(driver.page_source)
    except Exception as e:
        print(f"Không tìm thấy nút trang tiếp theo hoặc lỗi: {e}")
        break # Thoát nếu không tìm thấy nút

# Xử lý mã HTML của từng trang
for html_content in all_pages_html:
    tree = etree.HTML(html_content)
    # Định vị danh sách các mục dữ liệu (thay đổi XPath nếu cần)
    list_items = tree.xpath('//*[@id="dataList"]/li')
    for item in list_items:
        # Trích xuất thông tin từ mỗi mục
        name = item.xpath('./dl/@title')[0] # Ví dụ: lấy thuộc tính title
        print(name)

time.sleep(1)
driver.quit()

Ví dụ 2: Tự động Đăng nhập và Xử lý Mã xác nhận (Captcha)

Ví dụ này minh họa cách tự động đăng nhập vào một trang web (ví dụ: 12306) và xử lý mã xác nhận bằng dịch vụ nhận dạng ảnh bên thứ ba (như SuperEagle).

Thư viện hỗ trợ nhận dạng mã xác nhận (SuperEagle - ví dụ):

import requests
from hashlib import md5

class Chaojiying_Client(object):
    def __init__(self, username, password, soft_id):
        self.username = username
        password = password.encode('utf8')
        self.password = md5(password).hexdigest()
        self.soft_id = soft_id
        self.base_params = {
            'user': self.username,
            'pass2': self.password,
            'softid': self.soft_id,
        }
        self.headers = {
            'Connection': 'Keep-Alive',
            'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
        }

    def PostPic(self, im, codetype):
        # im: Dữ liệu byte của ảnh
        # codetype: Loại mã xác nhận (tham khảo trang web của dịch vụ)
        params = {'codetype': codetype}
        params.update(self.base_params)
        files = {'userfile': ('captcha.jpg', im)}
        r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
        return r.json()

    def ReportError(self, im_id):
        # im_id: ID của ảnh mã xác nhận bị lỗi
        params = {'id': im_id}
        params.update(self.base_params)
        r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
        return r.json()

# Hàm đóng gói để nhận dạng ảnh mã xác nhận
def recognize_captcha(image_path, captcha_type):
    # Thay 'your_username', 'your_password', 'your_soft_id' bằng thông tin của bạn
    client = Chaojiying_Client('your_username', 'your_password', 'your_soft_id')
    with open(image_path, 'rb') as f:
        image_data = f.read()
    result = client.PostPic(image_data, captcha_type) # Ví dụ: captcha_type = 9004
    return result['pic_str']

Sử dụng Selenium để đăng nhập và nhận dạng mã xác nhận:

# Cần cài đặt Pillow: pip install Pillow
from PIL import Image
from selenium.webdriver.common.action_chains import ActionChains
from selenium import webdriver
import time

# Thay thế bằng đường dẫn thực tế đến chromedriver của bạn
driver = webdriver.Chrome("path/to/chromedriver")
url = 'https://kyfw.12306.cn/otn/login/init' # URL đăng nhập 12306
driver.get(url)
time.sleep(2) # Đợi mã xác nhận hiển thị

# Nhập tên người dùng và mật khẩu
username_input = driver.find_element("id", "username")
username_input.send_keys("your_username") # Thay bằng tên người dùng của bạn

password_input = driver.find_element("id", "password")
password_input.send_keys("your_password") # Thay bằng mật khẩu của bạn

# --- Xử lý Mã xác nhận ---
# 1. Chụp ảnh toàn bộ trang đăng nhập
driver.save_screenshot("login_page.png")

# 2. Định vị phần tử ảnh mã xác nhận
captcha_image_element = driver.find_element("xpath", '//*[@id="loginForm"]/div/ul[2]/li[4]/div/div/div[3]/img') # XPath có thể thay đổi
location = captcha_image_element.location
size = captcha_image_element.size

# 3. Xác định tọa độ để cắt ảnh mã xác nhận
x1 = location['x']
y1 = location['y']
x2 = x1 + size['width']
y2 = y1 + size['height']
crop_area = (int(x1), int(y1), int(x2), int(y2))

# 4. Cắt ảnh và lưu lại
with Image.open("login_page.png") as img:
    captcha_img = img.crop(crop_area)
    captcha_img.save("captcha.png")

# 5. Sử dụng dịch vụ nhận dạng để lấy kết quả (ví dụ: tọa độ các điểm cần click)
# Thay '9004' bằng loại mã xác nhận phù hợp nếu cần
# Đảm bảo bạn đã cấu hình thông tin đăng nhập cho recognize_captcha
recognized_result = recognize_captcha("captcha.png", '9004')
print(f"Kết quả nhận dạng: {recognized_result}")

# 6. Xử lý kết quả và thực hiện nhấp chuột vào các khu vực được chỉ định
click_coordinates = []
if '|' in recognized_result:
    # Kết quả có nhiều điểm: "x1,y1|x2,y2|..."
    points = recognized_result.split('|')
    for point in points:
        x, y = map(int, point.split(','))
        click_coordinates.append([x, y])
else:
    # Kết quả chỉ có một điểm: "x,y"
    x, y = map(int, recognized_result.split(','))
    click_coordinates.append([x, y])

# 7. Thực hiện nhấp chuột
for coord in click_coordinates:
    x_offset, y_offset = coord
    ActionChains(driver).move_to_element_with_offset(captcha_image_element, x_offset, y_offset).click().perform()
    time.sleep(0.5) # Chờ một chút giữa các lần nhấp

# 8. Nhấp vào nút Đăng nhập
login_button = driver.find_element("id", "loginSub") # Thay đổi ID nếu cần
login_button.click()

time.sleep(3) # Đợi trang sau khi đăng nhập tải xong
driver.quit()

Thẻ: selenium webdriver web scraping python automation

Đăng vào ngày 14 tháng 11 lúc 16:24