Sử dụng proxy trong Scrapy

Giới thiệu

Scrapy là một framework chuyên được sử dụng để extracting data từ web. Nó cao hơn một tầng so với một số lib python cùng chức năng như Requests, BeautifulSoup, urrlib2...

Scrapy phù hợp cho những project chuyên biệt về crawl. Nó cung cấp CLI tools đầy đủ để phát triển nhanh một project.

Scrapy đơn giản và đầy đủ vì Scrapy cung cấp gần như đủ các function để phục vụ bạn crawl. Scrapy dễ dàng mở rộng ví dụ như kết hợp với Selenium để crawl những website sử dụng javascript. Với tài liệu đầy đủ, trực quan, người mới có thể tiếp xúc với Scrapy rất dễ dàng.

Một trong những vẫn đề khá là đau đầu khi crawl web đó là bị banned IP. Việc bạn request liên tục trong một khoảng thời gian ngắn chẳng khác nào việc DDOS cả. Đó là lý do, quản trị mạng con web mà bạn muốn crawl sẵn sàng banned IP tạm thời hoặc vĩnh viễn.

Kinh nghiệm của mình sau nhiều năm làm crawl có lẽ là tránh việc để họ bị banned IP. Còn nếu bị band rồi thì theo mình biết cách hữu hiệu nhất là sử dụng proxy. Hoặc, contact thẳng với bên website đó xin data cho nhanh 😄. Tóm lại, việc sử dụng proxy để crawl là cần thiết.

Scrapy hỗ trợ rất tốt việc sử dụng proxy. Và cách dử dụng proxy trong Scrapy cũng rất đơn giản.

Cài đặt

Các ứng dụng viết trên nền Python thì thường hoạt động tốt nhất với nền tảng Linux và tệ nhật với Windows. Ở đây, mình chỉ hướng dẫn nhanh cách cài đặt trên nền tảng Linux. Còn windows bạn có thể tham khảo ở đây

Yêu cầu:

  • Python: 2 hoặc 3
  • Pip hoặc Conda

Ở mức độ cơ bản, thì bạn có thể cài đặt thằng vào Python trên hệ thống. Còn nâng cao hơn, bạn có thể sử dụng virtualenv hay docker... Ở đây, mình không đi sau vào cài đặt nên chỉ hướng dẫn ở mức độ cơ bản

Lệnh cài đặt:

  • Với Pip:
pip install scrapy
  • Với Conda
conda install -c conda-forge scrapy 

Với lệnh này, bạn sẽ cài đặt scrapy lastversion. Nếu bạn muốn một version cụ thể ví dụ bạn muốn cài đặt version 0.24.6 - một version huyền thoại

pip install scrapy==0.24.6

Kiểm tra lại:

% python             
Python 3.6.1 (default, Nov  9 2017, 10:16:55) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import scrapy
>>> 

Done!

Tạo một project

Như đã nói ở trên Scrapy cung cấp CLI để tạo nhanh project.

Ở đây mình tạo một project lấy tên là extest

scrapy startproject extest

Cấu trúc project:


├── extest
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       ├── __init__.py
└── scrapy.cfg

Tạo một file tên là ballon.py trong thư mục spider

from scrapy import Spider, Request


class TestDev(Spider):
    name = "whatismyipaddress"

    def start_requests(self):
        urls = ['https://whatismyipaddress.com/']
        for url in urls:
            request = Request(url=url, callback=self.parse)
            yield request

    def parse(self, response):
        ip = response.xpath("//div[@id='main_content']/div[@id='section_left']/div[2]/a//text()").extract_first()
        print("Your ip {}".format(ip))
        return

spider này đơn giản chỉ là mình lấy ra IP hiện tại của mình. chạy thử nào:

% scrapy crawl whatismyipaddress                                                                                           
2017-12-27 10:49:27 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: extest)
2017-12-27 10:49:27 [scrapy.utils.log] INFO: Overridden settings: {'BOT_NAME': 'extest', 'DOWNLOAD_DELAY': 3, 'NEWSPIDER_MODULE': 'extest.spiders', 'ROBOTSTXT_OBEY': True, 'SPIDER_MODULES': ['extest.spiders']}
2017-12-27 10:49:27 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.memusage.MemoryUsage',
 'scrapy.extensions.logstats.LogStats']
2017-12-27 10:49:27 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2017-12-27 10:49:27 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2017-12-27 10:49:27 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2017-12-27 10:49:27 [scrapy.core.engine] INFO: Spider opened
2017-12-27 10:49:27 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2017-12-27 10:49:27 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2017-12-27 10:49:27 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://whatismyipaddress.com/robots.txt> (referer: None)
2017-12-27 10:49:32 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://whatismyipaddress.com/> (referer: None)
Your ip xxx.97.243.xxx
2017-12-27 10:49:32 [scrapy.core.engine] INFO: Closing spider (finished)
2017-12-27 10:49:32 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 510,
 'downloader/request_count': 2,
 'downloader/request_method_count/GET': 2,
 'downloader/response_bytes': 11213,
 'downloader/response_count': 2,
 'downloader/response_status_count/200': 2,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2017, 12, 27, 3, 49, 32, 730299),
 'log_count/DEBUG': 3,
 'log_count/INFO': 7,
 'log_count/WARNING': 1,
 'memusage/max': 51011584,
 'memusage/startup': 51011584,
 'response_received_count': 2,
 'scheduler/dequeued': 1,
 'scheduler/dequeued/memory': 1,
 'scheduler/enqueued': 1,
 'scheduler/enqueued/memory': 1,
 'start_time': datetime.datetime(2017, 12, 27, 3, 49, 27, 531919)}
2017-12-27 10:49:32 [scrapy.core.engine] INFO: Spider closed (finished)

Thêm option --nolog để chỉ hiện thị nội dung mình muốn print

% scrapy crawl whatismyipaddress --nolog
Your ip xxx.97.243.xxx

OK. xxx.97.243.xxx là IP hiện tại của mình

Sử dụng proxy

Đầu tiên là kiếm proxy. Google search ra rất nhiều bạn. Mà hàng free thì bạn biết đấy, có thể die bất cứ lúc nào. Nếu bạn xác định làm project về crawl thì mua proxy là điều mình nghĩ là cần thiết

Mình kiếm được một proxy là 165.227.186.129:80

Fake nào:

Đầu tiên là cấu hình lại code trong settings.py: thêm dòng này vào

DOWNLOADER_MIDDLEWARES = {
   'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 1,
}

Sau đó sửa lại file balloon.py

from scrapy import Spider, Request


class TestDev(Spider):
    name = "whatismyipaddress"

    def start_requests(self):
        urls = ['https://whatismyipaddress.com/']
        for url in urls:
            request = Request(url=url, callback=self.parse)
            request.meta["proxy"] = "http://165.227.186.129:80"
            yield request

    def parse(self, response):
        ip = response.xpath("//div[@id='main_content']/div[@id='section_left']/div[2]/a//text()").extract_first()
        print("Your ip {}".format(ip))
        return

Run again:

% scrapy crawl whatismyipaddress --nolog
Your ip 165.227.186.129

Perfect!

Đây là cách đơng giản nhất. Nếu bạn không muốn đặt proxy trong balloon.py, bạn có thể đặt trong middlewares.py

Add thêm một class vào bên dưới file:

class ProxyMiddleware(object):
    def process_request(self, request, spider):
        request.meta['proxy'] = "http://165.227.186.129:80"

Settings lại trong settings.py

DOWNLOADER_MIDDLEWARES = {
    'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 110,
    'extest.middlewares.ProxyMiddleware': 100,
}

Cơ bản là vậy. Để mở rộng hơn khi bạn có một list danh sách các proxy, bạn có thể đọc random trong class ProxyMiddleware để đạt được kết quả tốt nhất.

Trên đây là hướng dẫn sử dụng proxy trong Scrapy cơ bản. Nếu có góp ý, vui lòng comment phía bên dưới.

Cảm ơn bạn đã đọc bài!