如果您可以帮助我改进代码并解决以下两个问题,那将是很好的:
['DE101096','AT231']
开始时的其中一个transactionID transactionDate acq_id tra_id
DE101096 2011-02-21 11:05:23.312
DE101096 2011-02-21 11:05:23.312 Anlagenkonto Oxyfuelanlage
DE101096 2011-02-21 11:05:23.312 Anlagenkonto Oxyfuelanlage N ationalkonto - Ausgabe
我显然希望只有一行包含transactionID,transactionDate,acq_id和tra_id。我知道这个问题显然取决于我的代码,它将transactionID,transactionDate传递给由于后续两个请求而重复的项目。但是,我无法找到更接近预期输出的解决方案。
如何解决上述问题以及如何让我的蜘蛛更加有效。我也尝试过基于规则的方法,但这根本没有用。
我为所有投入感到高兴!
import csv
from scrapy.contrib.spiders import CrawlSpider
from scrapy.selector import Selector
from scrapy.contrib.linkextractors import LinkExtractor
from scrapy.http import FormRequest, Request
from etsbot.items import TransactionItem
from etsbot.middlewares import RandomProxy
class EuetsbotdetSpider(CrawlSpider):
name = 'euetsbotdet'
allowed_domains = ['ec.europa.eu']
start_urls = [
'http://ec.europa.eu/environment/ets/transaction.do'
]
def parse(self, response):
#self.data = csv.DictReader(open('/home/...t/items.csv','r'))
#self.tids = []
#for self.row in self.data:
# self.tids.append(self.row['transactionID'])
self.tids = ['DE101096','AT231']
for self.id in self.tids:
return FormRequest.from_response(
response,
formname='transactions_maxlength',
formdata={'transactionID':self.id},
clickdata={'name': 'search'},callback=self.parseLinks
)
def parseLinks(self,response):
lex = LinkExtractor(allow=('http://ec.europa.eu/environment/ets/singleTransaction.do',),unique=True)
for l in lex.extract_links(response):
yield Request(l.url,method='GET',callback=self.parseDetail,)
def parseDetail(self,response):
sel = Selector(response)
item = TransactionItem()
item['transactionID'] = sel.xpath('//table/tr/td/input[@name="transactionID"]/@value').extract()
item['transactionDate'] = sel.xpath('//table/tr/td/input[@name="transactionDate"]/@value').extract()
lext = LinkExtractor(unique=True,restrict_xpaths = ('//*[@id="tblTransactionBlocksInformation"]/tr/td[6]/a[@class="resultlink"]'),)
for l in lext.extract_links(response):
yield Request(l.url,method='GET',meta={'item':item},callback=self.parseAccounttr)
lexa = LinkExtractor(unique=True,restrict_xpaths = ('//*[@id="tblTransactionBlocksInformation"]/tr/td[7]/a[@class="resultlink"]'),)
for l in lexa.extract_links(response):
yield Request(l.url,method='GET',meta={'item':item},callback=self.parseAccountac)
yield item
def parseAccounttr(self,response):
sel = Selector(response)
item = response.meta['item']
item['tra_id'] = sel.xpath('//*[@id="tblAccountInfoReadonly"]/tr/td/input[@name="identifierInReg"]/@value').extract()
yield item
def parseAccountac(self,response):
sel = Selector(response)
item = response.meta['item']
item['acq_id'] = sel.xpath('//*[@id="tblAccountInfoReadonly"]/tr/td/input[@name="identifierInReg"]/@value').extract()
yield item
修改:
借助paul trmbrth的好评,我改写了我的代码。我没有像上面的代码那样在两组中拆分下载,而是在一个流中完成所有操作。这意味着当我为每个transactionID / transactionDate运行抓取spider.py -o时,我有两行,第一行是"卖家" "买方"。显然,这些信息应该在一行中。我现在的想法是在后处理中自动纠正这一点,即通过transactionID / transactionDate将每个奇数项与后续偶数项合并(我希望这是明确的)。但是我怎么能这样做呢?
import csv
from scrapy.contrib.spiders import CrawlSpider
from scrapy.selector import Selector
from scrapy.contrib.linkextractors import LinkExtractor
from scrapy.http import FormRequest, Request
from etsbot.items import TransactionItem
#from etsbot.middlewares import RandomProxy
from etsbot.inline_requests import inline_requests
class EuetsbotdetSpider(CrawlSpider):
name = 'euetsbotdet'
allowed_domains = ['ec.europa.eu']
start_urls = [
'http://ec.europa.eu/environment/ets/transaction.do'
]
def parse(self, response):
self.tids = ['DE101096']
for self.id in self.tids:
yield FormRequest.from_response(
response,
formname='transactions_maxlength',
formdata={'transactionID': self.id},
clickdata={'name': 'search'},
callback=self.parseDetail,
)
def parseDetail(self, response):
lex = LinkExtractor(allow= ('http://ec.europa.eu/environment/ets/singleTransaction.do',),unique=True)
for l in lex.extract_links(response):
yield Request(l.url, method='GET', callback = self.parseAccount)
def parseAccount(self, response):
sel = Selector(response)
self.transactionID = sel.xpath('//table/tr/td/input[@name="transactionID"]/@value').extract()
self.transactionDate = sel.xpath('//table/tr/td/input[@name="transactionDate"]/@value').extract()
lex = LinkExtractor(unique=True,restrict_xpaths=('//*[@id="tblTransactionBlocksInformation"]/tr/td/a[@class="resultlink"]'),)
for l in lex.extract_links(response):
yield Request(l.url,method='GET',callback=self.parseAgents)
def parseAgents(self,response):
sel = Selector(response)
ag = sel.xpath('//*[@id="tblAccountInfoReadonly"]/tr/td/input[@name="identifierInReg"]/@value').extract()
ah = sel.xpath('//*[@id="tblAccountInfoReadonly"]/tr/td/input[@name="accountHolder"]/@value').extract()
item = TransactionItem()
item['transactionID'] = self.transactionID
item['transactionDate'] = self.transactionDate
item['identifierInReg'] = ag
item['accountHolder'] = ah
yield item
答案 0 :(得分:1)
关于第1点,当你写:
for self.id in self.tids:
return FormRequest.from_response(
response,
formname='transactions_maxlength',
formdata={'transactionID':self.id},
clickdata={'name': 'search'},callback=self.parseLinks
)
循环在第一次迭代时停止,因为您使用return
。
将其更改为“yield
循环”:
for self.id in self.tids:
yield FormRequest.from_response(
response,
formname='transactions_maxlength',
formdata={'transactionID':self.id},
clickdata={'name': 'search'},callback=self.parseLinks
)
关于第二点,正如@EricValente所说,如果每个交易ID需要1个CSV行,则每个交易ID只需要产生/返回1个项目。
您可以开始在parseDetail
中构建项目,并在meta
中传递此项目,就像您正在做的那样,但是您需要跟踪有多少请求未知,以便知道何时返回处理完每个回复时的项目。
这样做可能非常棘手。例如,您必须捕获请求失败。
您可以尝试使用scrapy-inline-requests,这非常方便。
另一种选择是在第一次刮擦后按事务ID进行后处理和分组,因此您可以手动构建CSV。
另一个选择是不对parseAccounttr()
和parseAccountac()
执行这些额外请求:据我所知,在2个交易ID中,tr[6]
中链接的文本值tr[7]
中的parseDetail()
与您在后续回调中获取的identifierInReg
属性具有相同的值
答案 1 :(得分:0)
我没有测试过这段代码,但问题是你在scrape的不同部分放置了3次项目(这就是为什么它们每个只包含你要查找的字段的子集)。您最后只需要一个“收益项目”。我重写了代码,你可以在http://pastebin.com/dxsHZ7fZ找到它。