Giới thiệu
Trong các bài viết trước, chúng ta đã tìm hiểu về cách sử dụng Scrapy cơ bản và các phương pháp xử lý dữ liệu. Bài viết này sẽ hướng dẫn bạn một tính năng nâng cao của Scrapy đó là tự tạo middleware.
Middleware trong Scrapy đóng vai trò như một cầu nối giữa các thành phần khác nhau của framework. Cơ chế middleware linh hoạt cho phép chúng ta chèn logic tùy chỉnh vào quá trình xử lý request và response. Thông qua việc tự tạo middleware, bạn có thể thực hiện nhiều chức năng nâng cao như quản lý proxy, retry request, tùy chỉnh header, xử lý captcha và nhiều tác vụ khác.
Bài viết này sẽ giúp bạn nắm vững:
- Khái niệm cơ bản về middleware: Hiểu vai trò và cách hoạt động của middleware trong Scrapy.
- Cách tự tạo middleware: Từ việc tạo đến triển khai các chức năng tùy chỉnh.
- Các ứng dụng thực tế: Xử lý proxy, header, giới hạn tốc độ và các tác vụ khác.
- Cấu hình và kích hoạt middleware: Cách thiết lập để middleware hoạt động đúng.
- Debug và tối ưu: Kiểm tra và đảm bảo hiệu suất của middleware.
- Tự tạo Middleware trong Scrapy
Scrapy cung cấp sẵn nhiều middleware nhưng đôi khi chúng không đáp ứng được yêu cầu đặc thù của dự án. Chúng ta có thể tự tạo middleware bằng cách ghi đè các phương thức quan trọng. Dưới đây là ba ví dụ điển hình:
1.1. Middleware cho User-Agent ngẫu nhiên
Mục đích: Tránh bị phát hiện qua đặc điểm header và bị chặn request.
Các bước thực hiện:
- Tạo project và spider
scrapy startproject ua_demo
cd ua_demo
scrapy genspider useragent quotes.toscrape.com
- Cài đặt thư viện hỗ trợ
pip install fake-useragent
- Tạo file spider (useragent.py)
import scrapy
class UseragentSpider(scrapy.Spider):
name = "useragent"
def start_requests(self):
danh_sach_url = [
"http://quotes.toscrape.com/page/1/",
"http://quotes.toscrape.com/page/2/"
]
for url in danh_sach_url:
yield scrapy.Request(url=url, callback=self.xu_ly_du_lieu)
def xu_ly_du_lieu(self, response):
print("Thông tin User-Agent:", response.request.headers.get('User-Agent'))
- Tự tạo middleware (middlewares.py)
from fake_useragent import UserAgent
class RandomUserAgentMiddleware:
def __init__(self, crawler):
self.ua = UserAgent()
self.loai_trinh_duyet = crawler.settings.get("UA_TYPE", "chrome")
@classmethod
def from_crawler(cls, crawler):
return cls(crawler)
def process_request(self, request, spider):
request.headers['User-Agent'] = getattr(self.ua, self.loai_trinh_duyet)
- Cấu hình (settings.py)
DOWNLOADER_MIDDLEWARES = {
'ua_demo.middlewares.RandomUserAgentMiddleware': 400,
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None
}
UA_TYPE = "random" # Các tùy chọn: random/chrome/firefox/ie
1.2. Middleware xử lý Cookies để đăng nhập
Mục đích: Truy cập các trang yêu cầu xác thực mà không cần đăng nhập thủ công.
Các bước thực hiện:
- Tạo file spider (auth_spider.py)
import scrapy
class AuthSpider(scrapy.Spider):
name = 'auth_spider'
allowed_domains = ['example.com']
start_urls = ['https://www.example.com/dashboard']
def start_requests(self):
yield scrapy.Request(url=self.start_urls[0], callback=self.xu_ly_trang)
def xu_ly_trang(self, response):
print('Thông tin người dùng:', response.xpath('//span[@class="username"]/text()').extract_first())
- Tạo middleware xử lý cookies (middlewares.py)
class CookiesAuthMiddleware:
def __init__(self, cookies_string):
self.cookies_string = cookies_string
@classmethod
def from_crawler(cls, crawler):
return cls(
cookies_string = crawler.settings.get('COOKIES_STRING')
)
cookies = {}
def process_request(self, request, spider):
for item in self.cookies_string.split(';'):
key, value = item.split('=', 1)
self.cookies.__setitem__(key.strip(), value)
request.cookies = self.cookies
- Tạo middleware User-Agent ngẫu nhiên (middlewares.py)
from fake_useragent import UserAgent
class RandomHeaderMiddleware:
def __init__(self, crawler):
self.ua = UserAgent()
self.loai_trinh_duyet = crawler.settings.get("UA_TYPE", "chrome")
@classmethod
def from_crawler(cls, crawler):
return cls(crawler)
def process_request(self, request, spider):
request.headers.setdefault('User-Agent', getattr(self.ua, self.loai_trinh_duyet))
- Cấu hình (settings.py)
DOWNLOADER_MIDDLEWARES = {
'auth_demo.middlewares.CookiesAuthMiddleware': 201,
'auth_demo.middlewares.RandomHeaderMiddleware': 202,
'auth_demo.middlewares.DownloaderMiddleware': None,
}
COOKIES_STRING = "session=abc123; user_id=456; token=xyz789"
1.3. Middleware sử dụng Proxy IP ngẫu nhiên
Mục đích: Tránh bị chặn IP và tăng tỷ lệ thành công của request.
Các bước thực hiện:
- Tạo file spider (proxy_spider.py)
# -*- coding: utf-8 -*-
import scrapy
class ProxySpider(scrapy.Spider):
name = 'proxy_spider'
allowed_domains = ['httpbin.org']
start_urls = ['http://httpbin.org/get']
def start_requests(self):
yield scrapy.Request('http://httpbin.org/get', callback=self.xu_ly_response)
def xu_ly_response(self, response):
print(response.text)
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
if __name__=='__main__':
process = CrawlerProcess(get_project_settings())
process.crawl('proxy_spider')
process.start()
- Tạo middleware xử lý proxy (middlewares.py)
import random
class ProxyRotationMiddleware:
PROXY_LIST = [
'192.168.1.10:8080',
'192.168.1.11:8080',
'203.0.113.50:3128',
'198.51.100.25:8888'
]
def process_request(self, request, spider):
proxy = random.choice(self.PROXY_LIST)
request.meta['proxy'] = 'http://' + proxy
- Cấu hình (settings.py)
DOWNLOADER_MIDDLEWARES = {
'proxy_demo.middlewares.ProxyRotationMiddleware': 200,
'proxy_demo.middlewares.DownloaderMiddleware': None
}
1.4. Những điểm quan trọng cần lưu ý
- Thứ tự thực thi middleware: Được kiểm soát bằng giá trị số (100-900), số càng nhỏ càng được thực thi sớm.
- Kỹ thuật debug: Sử dụng
scrapy shellđể kiểm tra hoạt động của middleware. - Quy tắc tốt nhất:
- Kiểm tra tính hợp lệ của proxy IP định kỳ
- Lấy cookies từ trình duyệt sau khi đăng nhập thủ công
- Nên sử dụng loại "random" cho User-Agent
Cấu trúc project hoàn chỉnh:
project/
├── scrapy.cfg
└── project/
├── __init__.py
├── middlewares.py
├── settings.py
└── spiders/
├── __init__.py
├── useragent.py
├── auth_spider.py
└── proxy_spider.py