Bỏ để qua phần nội dung

Cách quét web bằng HTTPX và Python

Quét web là quá trình trích xuất dữ liệu từ các trang web một cách tự động. Đó là một kỹ thuật phổ biến được sử dụng để thu thập lượng lớn dữ liệu để phân tích, học máy và hơn thế nữa. Trong Python, có rất nhiều thư viện tuyệt vời giúp việc quét web trở nên dễ dàng. Một tùy chọn phổ biến là HTTPX.

HTTPX là một ứng dụng khách HTTP mạnh mẽ và hiện đại dành cho Python. Nó được tạo bởi các nhà phát triển đằng sau Yêu cầu và lấy rất nhiều cảm hứng từ Yêu cầu, đồng thời bổ sung thêm chức năng mới như hỗ trợ HTTP/2.

Trong hướng dẫn toàn diện này, chúng ta sẽ khám phá cách quét các trang web bằng Python một cách hiệu quả bằng HTTPX.

Bắt đầu với HTTPX

Để bắt đầu, HTTPX có thể được cài đặt qua pip:

pip install httpx

Ngoài ra, Thơ có thể được sử dụng:

poetry add httpx

Sau khi cài đặt, HTTPX có thể được nhập và sử dụng:

import httpx

response = httpx.get(‘https://example.com‘)
print(response.text)

Điều này sẽ tạo một yêu cầu NHẬN tới example.com và in HTML của trang chủ.

HTTPX có API đơn giản và hỗ trợ tất cả các động từ HTTP phổ biến như GET, POST, PUT, DELETE, HEAD, OPTIONS, v.v.

Một số tính năng chính bao gồm:

  • Hỗ trợ HTTP/1.1 và HTTP/2
  • API kiểu aiohttp không đồng bộ
  • Kết nối tổng hợp và giữ nguyên
  • Hỗ trợ proxy
  • Cấu hình thời gian chờ
  • Tính bền bỉ của cookie
  • API kiểu yêu cầu quen thuộc

Tiếp theo chúng ta hãy xem xét một số cách sử dụng phổ biến.

Thực hiện yêu cầu với HTTPX

Để thực hiện một yêu cầu GET, httpx.get() phương pháp có thể được sử dụng:

response = httpx.get(‘https://example.com‘)

Tương tự, httpx.post(), httpx.put(), httpx.delete(), v.v. có thể được sử dụng cho các động từ HTTP khác.

Các tham số như tiêu đề, cookie, thời gian chờ, v.v. có thể được chuyển vào dưới dạng đối số từ khóa:

response = httpx.get(
  ‘https://httpbin.org/headers‘,
  headers = {
    ‘User-Agent‘: ‘MyBot 1.0‘
  },
  timeout = 10.0
)

Phản hồi chứa các thuộc tính như status_code, headers, text, json()Vv:

print(response.status_code)
print(response.headers)
print(response.text)
json = response.json()

Bạn cũng có thể truyền phát phản hồi tăng dần bằng cách lặp lại đối tượng phản hồi.

Sử dụng máy khách HTTPX

Đối với hầu hết các tác vụ cạo, bạn nên sử dụng công cụ liên tục httpx.Client ví dụ.

Máy khách xử lý những thứ như tổng hợp kết nối, phiên, cookie, v.v. trên nhiều yêu cầu.

import httpx

client = httpx.Client()

response = client.get(‘https://example.com‘)
print(response.text)

response = client.get(‘https://httpbin.org/cookies/set?name=foo‘)
print(response.text) 

response = client.get(‘https://httpbin.org/cookies‘)
print(response.json())

Ở đây, chúng tôi thực hiện nhiều yêu cầu bằng cách sử dụng cùng một ứng dụng khách, ứng dụng này tự động xử lý việc lưu giữ cookie.

Bạn cũng có thể định cấu hình các tùy chọn như tiêu đề, proxy, xác thực, v.v. khi tạo ứng dụng khách:

client = httpx.Client(
  headers = {
    ‘User-Agent‘: ‘MyBot 1.0‘,
    ‘Authorization‘: ‘Bearer xxx‘   
  },
  proxies = ‘http://192.168.1.1:8181/‘,
  auth = (‘username‘, ‘password‘)
)

Bây giờ chúng ta hãy xem xét các yêu cầu tạo ra một cách không đồng bộ.

Yêu cầu không đồng bộ với HTTPX

Để thực hiện các yêu cầu không đồng bộ trong Python, HTTPX cung cấp một AsyncClient:

import httpx

async with httpx.AsyncClient() as client:
  response = await client.get(‘https://example.com‘) 

Chúng tôi sử dụng async with để khởi tạo ứng dụng khách, await theo yêu cầu và tự động đóng ứng dụng khách sau đó.

Để loại bỏ nhiều URL đồng thời, chúng ta có thể sử dụng asyncio.gather():

import httpx
import asyncio

async def get_url(url):
  async with httpx.AsyncClient() as client:
    response = await client.get(url)
    return response.text

urls = [‘https://example.com‘, ‘https://httpbin.org‘, ‘https://python.org‘]

async def main():
  responses = await asyncio.gather(*[get_url(url) for url in urls])
  print(responses)

asyncio.run(main())

asyncio.gather() đồng thời chờ đợi nhiều coroutine và trả về kết quả theo thứ tự chờ đợi.

Ngoài ra còn có các lựa chọn khác như asyncio.as_completed() để xử lý chúng khi chúng hoàn thành:

tasks = [get_url(url) for url in urls]

async def main():
  for result in asyncio.as_completed(tasks):
    print(await result)

Async IO cho phép tìm nạp đồng thời nhiều trang cùng một lúc, điều này rất hữu ích để tăng tốc độ thu thập dữ liệu.

Tiếp theo, hãy xem xét việc thu thập dữ liệu từ các phản hồi HTML và JSON.

Quét các phản hồi HTML và JSON

Để quét HTML, chúng ta có thể sử dụng trình phân tích cú pháp như Beautiful Soup để trích xuất dữ liệu:

from bs4 import BeautifulSoup

response = httpx.get(‘https://en.wikipedia.org/wiki/Python_(programming_language)‘)

soup = BeautifulSoup(response.text, ‘html.parser‘)

for link in soup.select(‘.toctext‘):
  print(link.text.strip())

Thao tác này sẽ in nội dung mục lục của trang Wikipedia.

Đối với các phản hồi JSON, HTTPX cung cấp tính năng tích hợp sẵn .json() phương pháp:

response = httpx.get(‘https://api.github.com/repos/encode/httpx‘)

json = response.json()
print(json[‘description‘])

Sản phẩm json= tham số cũng có thể được sử dụng để tuần tự hóa dữ liệu JSON trong các yêu cầu.

Cùng với trình phân tích cú pháp, chúng tôi có thể xây dựng trình thu thập dữ liệu để trích xuất dữ liệu từ API và trang web.

Xử lý sự cố và lỗi

Trong khi thu thập dữ liệu, thường có các vấn đề như lỗi kết nối, hết thời gian chờ, giới hạn tốc độ, v.v.

HTTPX cung cấp các ngoại lệ và công cụ để xử lý chúng một cách thích hợp.

Hết giờ

Để xử lý các phản hồi chậm, bạn có thể chỉ định một tùy chỉnh timeout tham số. Mặc định là 5 giây.

response = httpx.get(‘https://example.com‘, timeout=10.0) 

Nếu vượt quá điều này, một httpx.TimeoutException xảy ra:

try:
  response = httpx.get(‘https://example.com‘, timeout=0.001)
except httpx.TimeoutException:
  print(‘Request timed out‘)

Có thể cần thời gian chờ lâu hơn cho một số trang hoặc trang nhất định.

Lỗi HTTP

Đối với các lỗi HTTP như 400, 500, v.v. response.raise_for_status() phương pháp có thể được sử dụng:

try:
  response = httpx.get(‘https://httpbin.org/status/500‘)
  response.raise_for_status()
except httpx.HTTPStatusError:
  print(‘HTTP Error occurred‘)  

Điều này sẽ đưa ra một ngoại lệ đối với bất kỳ mã trạng thái 4xx hoặc 5xx nào.

Đang thử lại yêu cầu

Để thêm logic thử lại, các gói bên ngoài như tenacity có thể được sử dụng:

from tenacity import retry, stop_after_attempt

@retry(stop=stop_after_attempt(3))
def make_request():
  response = httpx.get(‘https://example.com‘)
  response.raise_for_status()
  return response.json()

data = make_request()

Ở đây chúng tôi thử lại tối đa 3 lần đối với bất kỳ ngoại lệ nào. Logic thử lại nâng cao hơn cũng có thể được xác định.

Giới hạn yêu cầu song song

Khi thực hiện nhiều yêu cầu song song, bạn có thể gặp phải giới hạn kết nối.

Sản phẩm limits tham số có thể được sử dụng để định cấu hình các tùy chọn như kết nối tối đa:

client = httpx.AsyncClient(
  limits = httpx.Limits(max_connections=20)
)

Điều chỉnh tham số này dựa trên trang đích có thể giúp tránh các giới hạn.

Bằng cách xử lý những vấn đề phổ biến này, bạn có thể tạo ra những chiếc máy cạo linh hoạt hơn.

Thu thập các phương pháp hay nhất

Dưới đây là một số mẹo để tạo trình dọn dẹp web hiệu quả với HTTPX:

  • Sử dụng ứng dụng khách HTTPX – Khách hàng cung cấp tính năng tổng hợp kết nối, tính bền vững của cookie và các lợi ích khác.

  • Cạo một cách lịch sự – Giới hạn tỷ lệ yêu cầu để tránh tình trạng quá tải máy chủ. Sử dụng độ trễ và điều chỉnh ngẫu nhiên.

  • Xử lý lỗi – Sử dụng các khối thử/ngoại trừ, kiểm tra trạng thái và thử lại để xử lý sự cố.

  • Sử dụng IO không đồng bộ – Quét các trang đồng thời để cải thiện tốc độ. Nhưng hạn chế đồng thời để tránh bị cấm.

  • Chọn ngẫu nhiên tác nhân người dùng – Xoay chuỗi tác nhân người dùng ngẫu nhiên để trông giống con người hơn.

  • Sử dụng proxy – Xoay các proxy/IP khác nhau để phân phối yêu cầu.

  • Bộ nhớ đệm và dữ liệu liên tục – Lưu dữ liệu đã cạo vào tập tin/cơ sở dữ liệu để tránh bị cạo lại.

Bằng cách làm theo các phương pháp hay nhất như thế này, bạn có thể tạo ra các công cụ dọn dẹp mạnh mẽ hơn và dễ bảo trì hơn.

Kỹ thuật cạo nâng cao

Hãy xem xét một số khả năng quét nâng cao hơn của HTTPX.

Quét các trang xác thực

Để loại bỏ các trang đã được xác thực, HTTPX hỗ trợ nhiều loại xác thực như xác thực Cơ bản, Digest và Bearer:

client = httpx.Client(
  auth = (‘username‘, ‘password‘)
)

response = client.get(‘https://api.example.com/users/me‘)

Thông tin xác thực được tự động lưu giữ qua các yêu cầu.

Xử lý cookie

Sản phẩm cookies tham số có thể được sử dụng để gửi cookie tùy chỉnh:

client = httpx.Client(
  cookies = {
    ‘sessionId‘: ‘xxxx‘
  }
)

response = client.get(‘https://example.com/dashboard‘) 

Và các cookie do máy chủ đặt sẽ tự động được lưu giữ trong máy khách.

Truyền phản hồi

Đối với các phản hồi lớn, bạn có thể truyền chúng dần dần bằng cách lặp lại đối tượng phản hồi:

response = client.get(‘https://example.com/bigfile‘)
for chunk in response:
  process(chunk) 

Điều này tránh phải tải toàn bộ phản hồi vào bộ nhớ.

Hỗ trợ proxy

Để định tuyến các yêu cầu thông qua máy chủ proxy, proxies tham số có thể được sử dụng:

proxy = ‘http://192.168.0.1:8888‘ 

client = httpx.Client(proxies = {‘http‘: proxy, ‘https‘: proxy})

Luân phiên các proxy khác nhau giúp phân phối yêu cầu từ các IP khác nhau.

Tiêu đề tùy chỉnh

Bạn có thể giả mạo hoặc ngẫu nhiên hóa các tiêu đề yêu cầu như tác nhân người dùng:

client = httpx.Client(headers = {
  ‘User-Agent‘: ‘MyBot 1.0‘ 
})

Điều này bắt chước các tiêu đề của một trình duyệt thực sự.

Thông qua các tính năng nâng cao hơn này, các trình dọn dẹp mạnh mẽ có thể được xây dựng bằng HTTPX và Python.

Dụng cụ nạo ví dụ

Bây giờ chúng ta hãy xem một số ví dụ về trình dọn dẹp được xây dựng bằng HTTPX.

Trình quét API Reddit

Đây là một công cụ quét cơ bản cho API Reddit:

import httpx

client = httpx.Client()

subreddit = ‘python‘ 
listing = ‘hot‘
limit = 10

response = client.get(f‘https://www.reddit.com/r/{subreddit}/{listing}.json?limit={limit}‘)

data = response.json()[‘data‘]

for post in data[‘children‘]:
   title = post[‘data‘][‘title‘]
   score = post[‘data‘][‘score‘]
   print(f"{title} (Score: {score})")

Thao tác này sẽ tìm nạp dữ liệu về các bài đăng hàng đầu từ subreddit Python. API trả về JSON mà chúng tôi có thể phân tích cú pháp.

Chúng tôi có thể mở rộng trình quét này để trích xuất dữ liệu từ nhiều subreddits, lưu trữ kết quả vào cơ sở dữ liệu, v.v.

Tin tức Điều Scraper

Đây là một công cụ thu thập tin tức đơn giản giúp trích xuất các bài viết từ một trang web:

from bs4 import BeautifulSoup
import httpx

client = httpx.Client()

response = client.get("https://example.com/news")
soup = BeautifulSoup(response.text, ‘html.parser‘)

for article in soup.select(‘.article‘):

  title = article.select_one(‘.article-title‘).text
  content = article.select_one(‘.article-content‘).text

  print(title) 
  print(content)
  print() 

Điều này tìm thấy tất cả .article các phần tử, trích xuất các trường tiêu đề và nội dung rồi in các bài viết.

Một lần nữa, điều này có thể được mở rộng để loại bỏ các trường bổ sung, phân tích ngày tháng, lưu trữ trong cơ sở dữ liệu, v.v.

Công cụ thu thập kết quả tìm kiếm

Và đây là một ví dụ về công cụ quét kết quả tìm kiếm của Google:

import httpx

query = "httpx python"
url = f"https://www.google.com/search?q={query}"

client = httpx.Client()
response = client.get(url)

from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, ‘html.parser‘)

for result in soup.select(‘.tF2Cxc‘):

  title = result.select_one(‘.DKV0Md‘).text
  link = result.select_one(‘.yuRUbf a‘)[‘href‘]

  print(title)
  print(link) 
  print()

Thao tác này sẽ tìm kiếm trên Google một truy vấn nhất định, phân tích các liên kết/tiêu đề kết quả và in chúng ra.

Một lần nữa, nhiều cải tiến có thể được thực hiện như trích xuất số lượng kết quả tìm kiếm, các trường bổ sung, trích xuất các trang kết quả, phát hiện hình ảnh xác thực, v.v.

Những ví dụ này minh họa các mẫu thu thập dữ liệu phổ biến với HTTPX. Các kỹ thuật tương tự có thể được áp dụng để xây dựng trình thu thập thông tin cho nhiều trang web và API.

Tổng kết

Tóm lại, HTTPX cung cấp một ứng dụng khách HTTP mạnh mẽ để xây dựng các trình quét web Python. Dưới đây là một số điểm chính:

  • HTTPX có API kiểu yêu cầu đơn giản để thực hiện yêu cầu.

  • Hỗ trợ Async cho phép thực hiện các yêu cầu đồng thời.

  • Xử lý lỗi mạnh mẽ với thời gian chờ, thử lại và kiểm tra trạng thái.

  • Dễ dàng loại bỏ các trang HTML bằng API Beautiful Soup và JSON.

  • Các máy khách liên tục cung cấp tính năng tổng hợp kết nối, phiên và xử lý cookie.

  • Các kỹ thuật nâng cao như proxy, tiêu đề và xác thực cho phép các trình dọn dẹp tinh vi.

  • Thực hiện theo các phương pháp hay nhất như sử dụng điều chỉnh, độ trễ ngẫu nhiên và tác nhân người dùng.

HTTPX giúp bạn dễ dàng bắt đầu tìm kiếm bằng Python. Với khả năng xử lý lỗi mạnh mẽ và tính đồng thời không đồng bộ, các trình dọn dẹp có thể mở rộng có thể được phát triển.

Hãy dùng thử HTTPX trong dự án quét web Python tiếp theo của bạn!

tags:

Tham gia vào cuộc đối thoại

Chúng tôi sẽ không công khai email của bạn. Các ô đánh dấu * là bắt buộc *