【问题标题】:How to save multiple URLs as file per StartURL in scrapy - python?如何在scrapy - python中将多个URL保存为每个StartURL的文件?
【发布时间】:2018-06-18 09:33:42
【问题描述】:

我有以下代码:

class VoteSpider(scrapy.Spider):
    name = "test"

    def start_requests(self):

        self.start_url = [
            "http://www.domain.de/URI.html?get=1&getX=2",
            "http://www.domain.de/URI.html?get=2&getX=3",
            "http://www.domain.de/URI.html?get=3&getX=4",
            "http://www.domain.de/URI.html?get=4&getX=5"            
        ]

        for url in self.start_url:
            self.a = 0
            self.url = url
            self.page = self.url.split("/")[-1]
            self.filename = '%s.csv' % self.page
            with open(self.filename, 'w') as f:
                f.write('URL:;'+self.url+'\n')

            yield scrapy.Request(url=self.url,callback=self.parse,dont_filter = True)

    def parse(self, response):
        sel = Selector(response)

        votes = sel.xpath('//div[contains(@class,"ratings")]/ul')

        with open(self.filename, 'a') as f:
            for vote in votes:
                self.a+=1
                f.write(str(self.a)+';'+vote.xpath('./li/text()').extract())

        if len(votes.xpath('//a[contains(@class,"next")]/@href').extract()) != 0:
            next_page = votes.xpath('//a[contains(@class,"next")]/@href').extract()[0]
            if next_page is not None:
                yield response.follow(next_page, callback=self.parse, dont_filter=True)

我的问题是,使用此代码,所有内容都将保存在一个文件中,在上面的示例中将是:

URI.html?get=1&getX=2.csv

由于我在多个 URL 上运行循环并为每个 URL 创建一个新文件名,我想知道哪里出了问题。

为什么这段代码没有为每个 URL 创建新文件?

for url in self.start_url:
    self.a = 0
    self.url = url
    self.page = self.url.split("/")[-1]
    self.filename = '%s.csv' % self.page
    with open(self.filename, 'w') as f:
        f.write('URL:;'+self.url+'\n')

有人可以告诉我正确的方法/示例如何保存每个起始 URL 的文件吗?请考虑一下,我还希望将以下页面附加到文件中,直到没有页面可以关注为止。

编辑:

问题不在于没有创建文件。的所有内容

with open(self.filename, 'a') as f:
            for vote in votes:
                self.a+=1
                f.write(str(self.a)+';'+vote.xpath('./li/text()').extract())

保存到一个文件中,而不是保存到 4 个文件中。所有将被保存到第一个可用的 StartURL

EDIT2:

这个主意不错!但从我的例子来看,它不能替换:

file_name = '%s.csv' % response.url.split("/")[-1]

因为 URI 正在更改,并且每个新 URI 都会创建一个新文件。

startURL 1     - "http://www.domain.de/URI.html?get=1&getX=2"
response.url 2 - "http://www.domain.de/URI.html?get=2&getX=2"
response.url 3 - "http://www.domain.de/URI.html?get=3&getX=2"

我只想保存 startURL 中的所有内容。

startURL 1     saved to "http://www.domain.de/URI.html?get=1&getX=2.csv"
response.url 2 saved to "http://www.domain.de/URI.html?get=1&getX=2.csv"
response.url 3 saved to "http://www.domain.de/URI.html?get=1&getX=2.csv"

一个不可靠的解决方案是按条件映射名称,但如果 startURL 数量增加或起始 URL 结构发生变化,则不实用:

if response.url.find("getX=2"):
    filename = self.start_url[0].split('/')[-1]
if response.url.find("getX=3"):
    filename = self.start_url[1].split('/')[-1]
if response.url.find("getX=4"):
    filename = self.start_url[2].split('/')[-1]
...

我不明白为什么self.filename 没有正确传递给self.parse()?是否有一些多重处理,所以self.filename 总是被第一项覆盖?如何在不使用响应对象的情况下转发正确的文件名?

解决方案:

我通过request.meta传递值:

class VoteSpider(scrapy.Spider):
    name = "test2"

    def start_requests(self):

        self.start_url = [
            "http://www.domain.de/URI.html?get=1&getX=2",
            "http://www.domain.de/URI.html?get=2&getX=3",
            "http://www.domain.de/URI.html?get=3&getX=4",
            "http://www.domain.de/URI.html?get=4&getX=5"          
        ]

        for url in self.start_url:
            self.a = 0
            self.url = url
            self.page = self.url.split("/")[-1]
            self.filename = '%s.csv' % self.page
            with open(self.filename, 'w') as f:
                f.write('URL:;'+self.url+'\n')
            request = scrapy.Request(url=self.url,callback=self.parse,dont_filter = True)
            request.meta['url'] = url
            yield request

    def parse(self, response):
        sel = Selector(response)

        votes = sel.xpath('//div[contains(@class,"ratings")]/ul')

        self.file = response.meta['url']
        filename = self.file.split("/")[-1]+'.csv'
        with open(filename, 'a') as f:
            for vote in votes:
                self.a+=1
                f.write(str(self.a)+';'+votes.xpath('./li/text()').extract()[0])

        if len(votes.xpath('//a[contains(@class,"next")]/@href').extract()) != 0:
            next_page = votes.xpath('//a[contains(@class,"next")]/@href').extract()[0]
            if next_page is not None:
                request = response.follow(next_page, callback=self.parse, dont_filter=True)
                request.meta['url'] = self.file
                yield request 

【问题讨论】:

  • 我运行这段代码,它生成了四个.csv文件
  • @zimdero 对!谢谢。我在编辑中指定了问题 - 我为文件创建的标头之后的所有以下数据都保存到一个文件中,而不是超过 4 个文件
  • 好的,我现在看看
  • @zimdo 这是一个好主意,但它仍然不适用于我的用例。还有其他想法或解释吗?谢谢!我又编辑了
  • 你能给我两个网址吗?试一试

标签: python python-3.x web-scraping scrapy web-crawler


【解决方案1】:

代替:

with open(self.filename, 'a') as f:
    ...

尝试使用这个,file_name 将是当前的request.url 例如:URI.html?get=1&getX=2.csv

file_name = '%s.csv' % response.url.split("/")[-1]
with open(file_name, 'a') as f:
    ...

【讨论】:

  • 你的评论给了我这个想法 :) 感谢你的努力!
  • 你认为我找到了一个干净的解决方案吗?
猜你喜欢
  • 1970-01-01
  • 2020-03-16
  • 2019-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-25
相关资源
最近更新 更多