首页 文章

使用Scrapy进行Python数据抓取

提问于
浏览
7

我想从一个有TextFields,Buttons等的网站上抓取数据 . 我的要求是填写文本字段并提交表单以获得结果,然后从结果页面中抓取数据点 .

我想知道Scrapy是否具有此功能,或者如果有人可以推荐Python中的库来完成此任务?

(编辑)的
我想从以下网站获取数据:
http://a836-acris.nyc.gov/DS/DocumentSearch/DocumentType

我的要求是从ComboBoxes中选择值并点击搜索按钮并从结果页面中抓取数据点 .

附:我必须在运行刮刀之前安装Firefox .

Selenium Firefox驱动程序为一个实例消耗大约100MB内存,我的要求是一次运行大量实例以使抓取过程快速,因此也存在内存限制 .

Firefox在执行刮刀时有时会崩溃,不知道为什么 . 此外,我需要窗口少刮,这在Selenium Firefox驱动程序的情况下是不可能的 .

我的最终目标是在Heroku上运行刮刀,我在那里拥有Linux环境,因此selenium Firefox驱动程序无法在Heroku上运行 . 谢谢

3 回答

  • 3

    基本上,您有很多工具可供选择:

    这些工具有不同的用途,但可以根据任务将它们混合在一起 .

    Scrapy是一种功能强大且非常智能的工具,用于抓取网站,提取数据 . 但是,当涉及到操纵页面时:单击按钮,填写表单 - 它变得更加复杂:

    • 有时,通过直接在scrapy中制作基础表单动作,可以很容易地模拟填写/提交表单

    • 有时,你必须使用其他工具来帮助scrapy - 比如机械化或硒

    如果您更具体地提出问题,那将有助于了解您应该使用或选择哪种工具 .

    看看有趣的scrapy和selenium混合物的例子 . 在这里,selenium任务是单击按钮并为scrapy项提供数据:

    import time
    from scrapy.item import Item, Field
    
    from selenium import webdriver
    
    from scrapy.spider import BaseSpider
    
    
    class ElyseAvenueItem(Item):
        name = Field()
    
    
    class ElyseAvenueSpider(BaseSpider):
        name = "elyse"
        allowed_domains = ["ehealthinsurance.com"]
        start_urls = [
        'http://www.ehealthinsurance.com/individual-family-health-insurance?action=changeCensus&census.zipCode=48341&census.primary.gender=MALE&census.requestEffectiveDate=06/01/2013&census.primary.month=12&census.primary.day=01&census.primary.year=1971']
    
        def __init__(self):
            self.driver = webdriver.Firefox()
    
        def parse(self, response):
            self.driver.get(response.url)
            el = self.driver.find_element_by_xpath("//input[contains(@class,'btn go-btn')]")
            if el:
                el.click()
    
            time.sleep(10)
    
            plans = self.driver.find_elements_by_class_name("plan-info")
            for plan in plans:
                item = ElyseAvenueItem()
                item['name'] = plan.find_element_by_class_name('primary').text
                yield item
    
            self.driver.close()
    

    更新:

    以下是关于如何在您的案例中使用scrapy的示例:

    from scrapy.http import FormRequest
    from scrapy.item import Item, Field
    from scrapy.selector import HtmlXPathSelector
    
    from scrapy.spider import BaseSpider
    
    
    class AcrisItem(Item):
        borough = Field()
        block = Field()
        doc_type_name = Field()
    
    
    class AcrisSpider(BaseSpider):
        name = "acris"
        allowed_domains = ["a836-acris.nyc.gov"]
        start_urls = ['http://a836-acris.nyc.gov/DS/DocumentSearch/DocumentType']
    
    
        def parse(self, response):
            hxs = HtmlXPathSelector(response)
            document_classes = hxs.select('//select[@name="combox_doc_doctype"]/option')
    
            form_token = hxs.select('//input[@name="__RequestVerificationToken"]/@value').extract()[0]
            for document_class in document_classes:
                if document_class:
                    doc_type = document_class.select('.//@value').extract()[0]
                    doc_type_name = document_class.select('.//text()').extract()[0]
                    formdata = {'__RequestVerificationToken': form_token,
                                'hid_selectdate': '7',
                                'hid_doctype': doc_type,
                                'hid_doctype_name': doc_type_name,
                                'hid_max_rows': '10',
                                'hid_ISIntranet': 'N',
                                'hid_SearchType': 'DOCTYPE',
                                'hid_page': '1',
                                'hid_borough': '0',
                                'hid_borough_name': 'ALL BOROUGHS',
                                'hid_ReqID': '',
                                'hid_sort': '',
                                'hid_datefromm': '',
                                'hid_datefromd': '',
                                'hid_datefromy': '',
                                'hid_datetom': '',
                                'hid_datetod': '',
                                'hid_datetoy': '', }
                    yield FormRequest(url="http://a836-acris.nyc.gov/DS/DocumentSearch/DocumentTypeResult",
                                      method="POST",
                                      formdata=formdata,
                                      callback=self.parse_page,
                                      meta={'doc_type_name': doc_type_name})
    
        def parse_page(self, response):
            hxs = HtmlXPathSelector(response)
    
            rows = hxs.select('//form[@name="DATA"]/table/tbody/tr[2]/td/table/tr')
            for row in rows:
                item = AcrisItem()
                borough = row.select('.//td[2]/div/font/text()').extract()
                block = row.select('.//td[3]/div/font/text()').extract()
    
                if borough and block:
                    item['borough'] = borough[0]
                    item['block'] = block[0]
                    item['doc_type_name'] = response.meta['doc_type_name']
    
                    yield item
    

    保存在 spider.py 并通过 scrapy runspider spider.py -o output.json 运行,在 output.json 中您会看到:

    {"doc_type_name": "CONDEMNATION PROCEEDINGS ", "borough": "Borough", "block": "Block"}
    {"doc_type_name": "CERTIFICATE OF REDUCTION ", "borough": "Borough", "block": "Block"}
    {"doc_type_name": "COLLATERAL MORTGAGE ", "borough": "Borough", "block": "Block"}
    {"doc_type_name": "CERTIFIED COPY OF WILL ", "borough": "Borough", "block": "Block"}
    {"doc_type_name": "CONFIRMATORY DEED ", "borough": "Borough", "block": "Block"}
    {"doc_type_name": "CERT NONATTCHMENT FED TAX LIEN ", "borough": "Borough", "block": "Block"}
    ...
    

    希望有所帮助 .

  • 2

    如果您只是想提交表单并从结果页面中提取数据,我会选择:

    Scrapy增加的 Value 确实在于它能够跟踪链接并抓取网站,如果你确切地知道你在寻找什么,我认为它不适合这项工作 .

  • 16

    我个人会使用mechanize,因为我没有任何scrapy经验 . 但是,为屏幕抓取而构建的名为scrapy目的的库应该可以完成任务 . 我会和他们两个人一起去看看哪个工作最好/最简单 .

相关问题