Hướng dẫn web crawler using python

91 / 100

Cách crawl dữ liệu web hay cách thu thập dữ liệu web là một thắc mắc của khá nhiều bạn. Lý do bởi hiện nay, có vô vàn các website ở đủ mọi lĩnh vực cung cấp cho chúng ta rất nhiều thông tin hữu ích. Đôi khi, chúng ta sẽ muốn tổng hợp lại các thông tin này lại một chỗ để có thể dễ dàng sử dụng, phân tích,… Do vậy, bài viết này Lập Trình Không Khó sẽ hướng dẫn bạn các kiến thức cơ bản nhất về cách crawl [thu thập] dữ liệu web và có một vài demo bằng ngôn ngữ Python.

Để có thể nắm được tốt nhất nội dung của bài viết này, người đọc nên có sẵn 1 số kiến thức/kinh nghiệm sau:

  • Nắm được cấu trúc của 1 website.
  • Có kiến thức về HTML, CSS selector, XPath
  • Có kiến thức căn bản về ngôn ngữ lập trình Python
  • Có am hiểu nhất định về Dev Tools của trình duyệt

Nếu bạn không có sẵn các chuyên môn yêu cầu phía trên thì cũng không cần quá lo lắng. Bạn vẫn có thể nắm được cơ chế hoạt động, các kiến thức cơ bản và thực hành cùng tụi mình.

Lưu ý 1: Các kiến thức trong bài này áp dụng cho các website không áp dụng cơ chế lazy load. Thường sẽ là các website tin tức hay các website nhỏ. Trong khi đó khá nhiều website có cơ chế lazy load thì ngoài các kiến thức cơ bản trong bài viết này, ta sẽ cần các kỹ thuật nâng cao hơn.

Lưu ý 2: Trong quá trình thực hành, bạn chú ý tránh spam làm ảnh hưởng tới hoạt động bình thường của các website. Nếu cần, nên chạy vào ban đêm và để tốc độ vừa phải.

Chúng ta cùng bắt đầu nhé!

  • Kiến thức crawl dữ liệu web
    • Mã nguồn của trang [Page source]
    • Tìm kiếm phần tử
      • Tìm kiếm theo CSS Selector
      • Tìm kiếm theo XPath
      • Cách lấy CSS Selector/XPath của phần tử
    • Các thư viện crawl dữ liệu trong Python
      • # Thư viện requests
      • # Thư viện beautifulsoup4
      • # Dành cho website phức tạp
  • Thực hành thu thập dữ liệu web
    • # Vd1. Thu thập thông tin bài báo CNN
    • # Vd2. Thu thập tag phổ biến trên StackOverflow
    • # Vd3. Sử dụng Github API yêu cầu đăng nhập
    • # Ví dụ sử dụng Selenium
  • Bài viết liên quan

Kiến thức crawl dữ liệu web

Mã nguồn của trang [Page source]

Mọi web page của một trang web bất kỳ mà bạn nhìn thấy đều được trình duyệt vẽ lên từ 1 source code [bao gồm: html, css, js, json,…] mà máy chủ của website đó trả về cho trình duyệt.

Mỗi khi bạn yêu cầu xem 1 trang nào đó [ví dụ: truy cập url facebook.com], thì trình duyệt sẽ gửi yêu cầu đó về máy chủ. Máy chủ xử lý yêu cầu và gửi phản hồi lại là 1 source code [page source, do webserver sinh ra]. Trình duyệt tiếp nhận page source này và hiển thị nội dung đẹp đẽ cho chúng ta coi.

Tất cả những gì trình duyệt hiện lên [cái chúng ta thấy] đều được lấy từ page source đó. Do vậy, về nguyên lý thì tất cả những gì bạn thấy trên trang web đều có thể thu thập được bằng ngôn ngữ lập trình.

Vậy, nếu chúng ta dùng ngôn ngữ lập trình để gửi yêu cầu tới một url nào đó, thì cái chúng ta nhận được cũng sẽ là page source. Và việc cần làm của chúng ta là tìm nội dung mình cần trong cái page source đó.

Lưu ý:

  1. Bạn có thể xem page source của 1 trang web bất kỳ bằng tổ hợp phím Ctrl + U hoặc kiểm tra phần tử bằng tổ hợp Ctrl + Shift + I. Với MacOS thì thay Ctrl bằng Cmd, bạn cũng có thể thấy chúng khi click chuột phải trên trang.
  2. Một số website sẽ chặn cách phía trên, ta vẫn có thể xem mã nguồn trên trình duyệt bằng cách truy cập địa chỉ: view-source: như cách ta truy cập 1 trang web.
  3. Bạn cần có kiến thức cơ bản về HTML, CSS, JS để có thể hiểu mã nguồn này. Nếu không, bạn có thể thử tìm kiếm [Ctrl + F] từ khóa mình cần thử xem có không.

Mã nguồn của trang [page source] là dữ liệu có cấu trúc. Chúng ta hoàn toàn có thể biểu diễn nó dưới dạng cấu trúc dữ liệu Tree [cây]. Qua đó, bạn có thể duyệt qua từng node trên cây, tìm kiếm và lấy giá trị của node bất kỳ trên cây đó.

Tìm kiếm phần tử

Khi có được mã nguồn của trang, chúng ta sẽ tìm kiếm đến những vị trí mà ta cần để lấy dữ liệu cần thiết. Quá trình đó có thể thực hiện bằng một số cách dưới đây:

Tìm kiếm theo CSS Selector

Nếu bạn đã từng dùng JS hoặc JQuery thì chắc không còn lạ với CSS Selector. Từ mã nguồn sau khi được “làm đẹp”, chúng ta có thể dùng css selector để đi tới phần tử chúng ta cần.

Lấy ví dụ một đoạn mã nguồn sau:

  Danhsách website

  

    luyencode.net

  

  

    nguyenvanhieu.vn

  

  • Giá trị của các thuộc tính id [ex: top-site] thường sẽ là duy nhất trên mỗi webpage. Trong selecter thì class đại diện bởi dấu thăng [#] trước nó.
  • Giá trị của các thuộc tính class [ex: container, item, col-xs-6] có thể lặp lại nhiều lần trên mỗi webpage. Trong selecter thì class đại diện bởi dấu chấm [.] trước nó.
  • Các thẻ [ex: div, h3, p,…] là các tagname.

Ví dụ dùng css selector để tìm tới thẻ h3 có chứa giá trị Danh sách website:

  • div.container > h3#top-site
  • div > h3#top-site
  • #top-site

Tìm kiếm theo XPath

Nếu coi page source là một file xml thì ta có cách tìm kiếm theo XPath. Ví dụ dùng css selector để tìm tới thẻ h3 [trong ví dụ trên] có chứa giá trị Danh sách website:

  • /html/body/div/h3
  • //*[@id=”top-site”]

Về cách này, mình không quá rành nên xin phép không bàn thêm.

Cách lấy CSS Selector/XPath của phần tử

Trên trình duyệt, bạn cũng có thể dễ dàng copy selector hoặc xpath bằng cách chuột phải vào phần tử tại Dev Tools [Ctrl + Shift + I] như hình dưới đây:

Cách copy CSS Selector hoặc XPath trên Dev Tools của trình duyệt

Xem gif để dễ hình dung hơn cách lấy xpath/css selector của một phần tử bất kỳ:

Cách lấy xpath, selector của một element trên webpage

Quy trình: Đặt chuột vào phần tử cần lấy -> Click chuột phải -> Inspect -> Chuột phải vào source của nó -> Copy -> Copy Selector/Xpath.

Các thư viện crawl dữ liệu trong Python

Có thể nói, Python là ngôn ngữ đơn giản nhất giúp bạn có thể viết script crawl dữ liệu website nhanh chóng. Lý do bởi bản thân ngôn ngữ nó hỗ trợ rất tốt, lại còn kho tàng thư viện có sẵn hỗ trợ tận răng. Đó cũng là lý do mình chọn ngôn ngữ này để demo trong bài viết này.

# Thư viện requests

Với thư viện này, bạn có thể dễ dàng thực hiện gửi các yêu cầu [request] tới địa chỉ bất kỳ. Sau đó bạn sẽ nhận được phản hồi dưới dạng page source. Các chức năng cơ bản của thư viện này:

  • Tạo request, có thể có tham số [url params, body params, …] theo method bất kỳ [GET, POST, …]
  • Đọc phản hồi của máy chủ ở các format khác nhau [raw, json, media, …]
  • Gửi kèm Cookies, Auth, …

Thông tin thêm:

  • Cài đặt: pip install requests
  • Source: //docs.python-requests.org/en/latest/

# Thư viện beautifulsoup4

Thư viện này sẽ hỗ trợ bạn “làm đẹp” cái source mà bạn nhận được mỗi khi gửi request. Sau khi làm đẹp, bạn có thể thực hiện mọi thao tác tìm kiếm, trích xuất giá trị mà mình cần tìm từ source.

Thông tin thêm:

  • Cài đặt: pip install beautifulsoup4
  • Source: //www.crummy.com/software/BeautifulSoup/

# Dành cho website phức tạp

Với các website sử dụng cơ chế lazy load phức tạp. Các thành phần trên web chỉ yêu cầu tới máy chủ khi người dùng đang xem nó. Khi đó, một webpage mà bạn thấy được tạo ra bởi nhiều hơn 1 request [vd: Facebook, Instagram, …] đều có cơ chế này.

  • selenium
  • scrapy

Ưu điểm của các thư viện này là chúng giả lập trình duyệt luôn, nên không bỏ sót bất kỳ request nào. Nhưng như vậy ta phải tải tất cả nội dung mà có thể chẳng cần đến, dẫn đến quá trình thu thập sẽ chậm hơn nhiều.

Do đây là bài hướng dẫn cơ bản, mình sẽ không đi sâu vào dạng phức tạp này.

Thực hành thu thập dữ liệu web

Trong mục này, chúng ta sẽ cùng thực hành một vài ví dụ thực tế cách crawl dữ liệu web với ngôn ngữ Python.

# Vd1. Thu thập thông tin bài báo CNN

Trong ví dụ này, mình sẽ sử dụng ngôn ngữ Python và các thư viện requests, beautifulsoup để lấy các thông tin cần thiết từ 1 bài báo trên CNN.

  • Cài các thư viện cần dùng: pip install requests beautifulsoup4 lxml
  • Xem trước URL: //edition.cnn.com/2021/10/03/uk/everard-uk-police-gbr-cmd-intl/index.html

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

importrequests

frombs4 importBeautifulSoup

url="//edition.cnn.com/2021/10/03/uk/everard-uk-police-gbr-cmd-intl/index.html"

# Gửi 1 request đến url phía trên và nhận lại source page của nó

r= requests.get[url]

print[r.status_code]# 200 là thành công

# In thử page source ra coi sao, mình in thử 1000 ký tự đầu tiên thôi

# Bạn có thể thử so sánh với source mà bạn thấy trên trình duyệt

print[r.content[:1000]]

# Làm đẹp source

# Mình dùng lxml parser cho nhanh,

# Ngoài ra có html.parser, lxml-xml, html5lib [//www.crummy.com/software/BeautifulSoup/bs4/doc/]

soup=BeautifulSoup[r.content,'lxml']

print["============TITLE============="]

# Lấy thẻ tiêu đề bài báo

print[soup.title]

# Lấy nội dung tiêu đề

print[soup.title.text]

# Lấy ảnh đại diện của bài báo

# Ta tìm selector của nó theo hướng dẫn ở trên rồi dùng hàm select_one để tìm 1 phần tử đầu tiên

print["============FEATURE IMAGE============="]

feature_image=soup.select_one['#large-media > div > img']

print[feature_image.get['src-large']]

# Lấy nội dung bài

print["============CONTENT============="]

# Mình kiểm tra phần tử thì thấy nội dung bài nằm trong section id="body-text"

content_ele=soup.select_one["#body-text"]

print[content_ele.text]

# Lấy tác giả bài viết, ngay phía dưới tiêu đề và phía trên ảnh đại diện

# By Kara Fox, CNN

print["============AUTHOR============="]

author_ele=soup.select_one['body > div.pg-right-rail-tall.pg-wrapper > article > div.l-container > div.metadata > div > p.metadata__byline > span > a']

print[author_ele.text]

Kết quả thực thi:

200

b'

Chủ Đề