У меня есть следующий код:
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-адреса стартового 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
вместо:
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:
...