我已经在Scrapy中写了一个webscraper,最初进入this网页,抓取每个故障单的故障单信息,然后抓到每个链接上的" ticket"按钮重定向到。在故障单页面上,为了获得价格,必须要求JSON file(现在不是问题),需要提取文件中的第一个价格并保存到一个Scrapy项目加载器。
我尝试使用以下语句在scrapy shell中找到price对象:
jsonresponse = json.loads(response.body_as_unicode())
jsonresponse["p"]
和
jsonresponse["lp"]
和
jsonresponse['hp']
但由于某些原因,他们都没有在文件中找到价格对象。如果您查看tickets page,您会发现最低价格目前是28美元。对于这个特定的链接,我需要得到28美元的字符串。
我知道scrapy不能处理javascript,并且scrapy.js可用于将js集成到scrapy中,但我不确定是否应该在这种情况下使用它。无论如何,找到这个对象并将其提取到变量中的正确方法是什么。任何帮助,将不胜感激。谢谢! [编辑]以下是目前的代码:
bandname = raw_input("Enter a bandname \n")
vs_url = "http://www.vividseats.com/concerts/" + bandname + "-tickets.html"
class MySpider(CrawlSpider):
handle_httpstatus_list = [416]
name = 'comparator'
allowed_domains = ["www.vividseats.com"]
start_urls = [vs_url]
tickets_list_xpath = './/*[@itemtype="http://schema.org/Event"]'
def parse_json(self, response):
loader = response.meta['loader']
#not sure what to put here yet
return loader.load_item()
def parse_price(self, response):
loader = response.meta['loader']
ticketLink = loader.get_output_value("ticketsLink")
json_id_list= re.findall(r"\d{2,9}", ticketsLink)
json_id= "".join(json_id_list)
json_url = "www.vividseats.com/javascript/tickets.shtml?productionId=" + json_id
yield scrapy.Request(json_url, meta={'loader': loader}, callback = self.parse_json, dont_filter = True)
def parse(self, response):
"""
"""
selector = HtmlXPathSelector(response)
# iterate over tickets
for ticket in selector.select(self.tickets_list_xpath):
loader = XPathItemLoader(ComparatorItem(), selector=ticket)
# define loader
loader.default_input_processor = MapCompose(unicode.strip)
loader.default_output_processor = Join()
# iterate over fields and add xpaths to the loader
loader.add_xpath('eventName' , './/*[@class="productionsEvent"]/text()')
loader.add_xpath('eventLocation' , './/*[@class = "productionsVenue"]/span[@itemprop = "name"]/text()')
loader.add_xpath('ticketsLink' , './/*/a[@class = "btn btn-primary"]/@href')
loader.add_xpath('eventDate' , './/*[@class = "productionsDate"]/text()')
loader.add_xpath('eventCity' , './/*[@class = "productionsVenue"]/span[@itemprop = "address"]/span[@itemprop = "addressLocality"]/text()')
loader.add_xpath('eventState' , './/*[@class = "productionsVenue"]/span[@itemprop = "address"]/span[@itemprop = "addressRegion"]/text()')
loader.add_xpath('eventTime' , './/*[@class = "productionsTime"]/text()')
print "Here is ticket link \n" + loader.get_output_value("ticketsLink")
ticketsURL = "concerts/" + bandname + "-tickets/" + bandname + "-" + loader.get_output_value("ticketsLink")
ticketsURL = urljoin(response.url, ticketsURL)
yield scrapy.Request(ticketsURL, meta={'loader': loader}, callback = self.parse_price, dont_filter = True)
答案 0 :(得分:1)
我们以this url为例;
所有故障单信息对应上面的链接here,从那里你只需要将json的字段映射到html(html页面中的故障单信息 )。
In [1]: ticket_info = jsonresponse.get('tickets')
In [2]: ticket_info
Out[2]:
[{u'c': u'30611',
u'd': u'1000',
u'e': u'1',
u'f': u'1',
u'g': u'0',
u'h': u'',
u'i': u'VB844757004',
u'ind': u'1',
u'l': u'GA Main Floor',
u'n': u'Instant Download.',
u'p': u'27.00',
u'q': u'3',
u'r': u'G2',
u'rhdn': u'0',
u's': u'GA Main Floor',
u'sd': u'0',
u't': u'1',
u'v': u'',
u'z': u'0'},
{u'c': u'30611',
u'd': u'1000',
u'e': u'1',
u'f': u'1',
u'g': u'0',
u'h': u'',
u'i': u'VB891598272',
u'ind': u'1',
u'l': u'GA Main Floor',
u'n': u'Instant Download.',
u'p': u'29.00',
u'q': u'1',
u'r': u'G3',
u'rhdn': u'0',
u's': u'GA Main Floor',
u'sd': u'0',
u't': u'0',
u'v': u'',
u'z': u'0'},
{u'c': u'30611',
u'd': u'1000',
u'e': u'1',
u'f': u'0',
u'g': u'0',
u'h': u'',
u'i': u'VB900500475',
u'ind': u'0',
u'l': u'GA MAIN FLOOR',
u'n': u'',
u'p': u'30.00',
u'q': u'2',
u'r': u'G4',
u'rhdn': u'0',
u's': u'GA MAIN F..',
u'sd': u'0',
u't': u'0',
u'v': u'',
u'z': u'0'},
{u'c': u'30613',
u'd': u'3000',
u'e': u'1',
u'f': u'0',
u'g': u'0',
u'h': u'',
u'i': u'VB886172318',
u'ind': u'1',
u'l': u'GA Second Balcony - Limited View',
u'n': u'eTicket,Obstructed/Limited View Instant Download.',
u'p': u'37.00',
u'q': u'1',
u'r': u'GA',
u'rhdn': u'0',
u's': u'GA Second Balcony - Limited View',
u'sd': u'0',
u't': u'1',
u'v': u'',
u'z': u'0'},
{u'c': u'30611',
u'd': u'1000',
u'e': u'1',
u'f': u'1',
u'g': u'0',
u'h': u'',
u'i': u'VB806449210',
u'ind': u'1',
u'l': u'GA MAIN FLOOR',
u'n': u'eTicket Instant Download.',
u'p': u'39.00',
u'q': u'8',
u'r': u'GA',
u'rhdn': u'0',
u's': u'GA MAIN F..',
u'sd': u'0',
u't': u'1',
u'v': u'',
u'z': u'0'},
{u'c': u'30612',
u'd': u'2000',
u'e': u'1',
u'f': u'0',
u'g': u'0',
u'h': u'',
u'i': u'VB900500473',
u'ind': u'1',
u'l': u'GA First Balcony',
u'n': u'Instant Download.',
u'p': u'46.00',
u'q': u'2',
u'r': u'G3',
u'rhdn': u'0',
u's': u'GA First Balcony',
u'sd': u'0',
u't': u'0',
u'v': u'',
u'z': u'0'},
{u'c': u'30611',
u'd': u'1000',
u'e': u'1',
u'f': u'0',
u'g': u'0',
u'h': u'',
u'i': u'VB893201517',
u'ind': u'1',
u'l': u'GA Main Floor',
u'n': u'Instant Download.',
u'p': u'50.00',
u'q': u'6',
u'r': u'G5',
u'rhdn': u'0',
u's': u'GA Main Floor',
u'sd': u'0',
u't': u'3',
u'v': u'',
u'z': u'0'},
{u'c': u'30615',
u'd': u'995',
u'e': u'1',
u'f': u'0',
u'g': u'0',
u'h': u'07/19/15',
u'i': u'VB900847659',
u'ind': u'0',
u'l': u'GA',
u'n': u'Tickets will be ready for delivery by 07/19/2015.',
u'p': u'53.00',
u'q': u'4',
u'r': u'GA',
u'rhdn': u'0',
u's': u'GA',
u'sd': u'0',
u't': u'0',
u'v': u'',
u'z': u'0'},
{u'c': u'30615',
u'd': u'995',
u'e': u'1',
u'f': u'0',
u'g': u'0',
u'h': u'07/19/15',
u'i': u'VB900847710',
u'ind': u'0',
u'l': u'GA',
u'n': u'Tickets will be ready for delivery by 07/19/2015.',
u'p': u'53.00',
u'q': u'3',
u'r': u'GA',
u'rhdn': u'0',
u's': u'GA',
u'sd': u'0',
u't': u'0',
u'v': u'',
u'z': u'0'},
{u'c': u'30612',
u'd': u'2000',
u'e': u'1',
u'f': u'0',
u'g': u'0',
u'h': u'',
u'i': u'VB900500474',
u'ind': u'1',
u'l': u'GA First Balcony',
u'n': u'Instant Download.',
u'p': u'57.00',
u'q': u'8',
u'r': u'G2',
u'rhdn': u'0',
u's': u'GA First Balcony',
u'sd': u'0',
u't': u'3',
u'v': u'',
u'z': u'0'},
{u'c': u'30611',
u'd': u'1000',
u'e': u'1',
u'f': u'0',
u'g': u'0',
u'h': u'',
u'i': u'VB880887546',
u'ind': u'0',
u'l': u'GA Main Floor',
u'n': u'eTicket',
u'p': u'61.00',
u'q': u'4',
u'r': u'GA',
u'rhdn': u'0',
u's': u'GA Main Floor',
u'sd': u'0',
u't': u'1',
u'v': u'',
u'z': u'0'},
{u'c': u'30611',
u'd': u'1000',
u'e': u'1',
u'f': u'0',
u'g': u'0',
u'h': u'',
u'i': u'VB893198548',
u'ind': u'1',
u'l': u'GA Main Floor',
u'n': u'Instant Download.',
u'p': u'85.00',
u'q': u'8',
u'r': u'G4',
u'rhdn': u'0',
u's': u'GA Main Floor',
u'sd': u'0',
u't': u'3',
u'v': u'',
u'z': u'0'},
{u'c': u'30611',
u'd': u'1000',
u'e': u'1',
u'f': u'0',
u'g': u'0',
u'h': u'',
u'i': u'VB893198623',
u'ind': u'1',
u'l': u'GA Main Floor',
u'n': u'Instant Download.',
u'p': u'94.00',
u'q': u'2',
u'r': u'G4',
u'rhdn': u'0',
u's': u'GA Main Floor',
u'sd': u'0',
u't': u'0',
u'v': u'',
u'z': u'0'},
{u'c': u'30611',
u'd': u'1000',
u'e': u'1',
u'f': u'1',
u'g': u'0',
u'h': u'',
u'i': u'VB844757006',
u'ind': u'1',
u'l': u'GA Main Floor',
u'n': u'Instant Download.',
u'p': u'88.00',
u'q': u'8',
u'r': u'G3',
u'rhdn': u'0',
u's': u'GA Main Floor',
u'sd': u'0',
u't': u'1',
u'v': u'',
u'z': u'0'},
{u'c': u'30615',
u'd': u'995',
u'e': u'0',
u'f': u'0',
u'g': u'0',
u'h': u'07/19/15',
u'i': u'VB793104621',
u'ind': u'0',
u'l': u'GA',
u'n': u'Tickets will be ready for delivery by 07/19/2015.',
u'p': u'91.00',
u'q': u'8',
u'r': u'GA',
u'rhdn': u'0',
u's': u'GA',
u'sd': u'0',
u't': u'3',
u'v': u'',
u'z': u'0'},
{u'c': u'30611',
u'd': u'1000',
u'e': u'1',
u'f': u'1',
u'g': u'0',
u'h': u'',
u'i': u'VB844757008',
u'ind': u'1',
u'l': u'GA Main Floor',
u'n': u'Instant Download.',
u'p': u'111.00',
u'q': u'8',
u'r': u'G4',
u'rhdn': u'0',
u's': u'GA Main Floor',
u'sd': u'0',
u't': u'1',
u'v': u'',
u'z': u'0'},
{u'c': u'30611',
u'd': u'1000',
u'e': u'0',
u'f': u'0',
u'g': u'0',
u'h': u'07/16/15',
u'i': u'VB791993584',
u'ind': u'0',
u'l': u'GA Main Floor',
u'n': u'Zone Seating. The seller is committing to procure these tickets for you upon receipt of your order. After you place your order and your order is confirmed, we guarantee that your tickets will be within the listed zone or section listed or one comparable and that you will receive these tickets in time for the event or your money back. Orders exceeding four tickets may be split up into different rows within the requested zone or section.',
u'p': u'170.00',
u'q': u'6',
u'r': u'GA',
u'rhdn': u'0',
u's': u'GA Main Floor',
u'sd': u'0',
u't': u'3',
u'v': u'',
u'z': u'1'}]
ticket_info
是从低价到高价的票证信息列表。现在只从上面的列表中提取price-info
。
p
是与票价相对应的关键字。使用这些信息,它会给你这样的东西,
In [3]: price_list = [i.get('p') for i in ticket_info]
In [4]: price_list
Out[4]:
[u'27.00',
u'29.00',
u'30.00',
u'37.00',
u'39.00',
u'46.00',
u'50.00',
u'53.00',
u'53.00',
u'57.00',
u'61.00',
u'85.00',
u'94.00',
u'88.00',
u'91.00',
u'111.00',
u'170.00']
为了确保您获得最低价格,您可以执行price_list.sort()
并获取其中的第一个元素。