Scraping Tripadvisor attractions using scrapy and python - python
I am trying to scrape TripAdvisor's attractions, but I cannot get the names and addresses of each attraction. I suspect I wrote product.css(...) wrong (there are jsons?).
Can anyone tell me how to correct the code to get the name and address of each attraction?
My current code:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'https://www.tripadvisor.com/Attractions-g187427-Activities-oa90-Spain'
]
def parse(self, response):
for link in response.css('.EsZYd a::attr(href)'):
yield response.follow(link.get(), callback=self.parse_categories)
def parse_categories(self, response):
products = response.css('div.eeqnt')
for product in products:
yield {
'name' : product.css('h1.WlYyy cPsXC GeSzT::text').get().strip(),
'address' : product.css('span.WlYyy cacGK Wb::text').get().strip(),
}
Updated code (exporting infro from each atrraction on each page from list):
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'https://www.tripadvisor.com/Attractions-g274862-Activities-a_allAttractions.true-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa30-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa60-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa90-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa120-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa150-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa180-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa210-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa240-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa270-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa300-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa330-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa360-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa390-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa420-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa450-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa480-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa510-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa540-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa570-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa600-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa630-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa660-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa690-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa720-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa750-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa780-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa810-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa840-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa870-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa900-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa930-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa960-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa990-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1020-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1050-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1080-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1110-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1140-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1170-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1200-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1230-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1260-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1290-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1320-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1350-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1380-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1410-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1440-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1470-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1500-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1530-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1560-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1590-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1620-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1650-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1680-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1710-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1740-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1770-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1800-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1830-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1860-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1890-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1920-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1950-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa1980-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2010-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2040-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2070-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2100-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2130-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2160-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2190-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2220-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2250-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2280-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2310-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2340-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2370-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2400-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2430-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2460-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2490-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2520-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2550-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2580-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2610-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2640-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2670-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2700-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2730-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2760-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2790-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2820-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2850-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2880-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2910-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2940-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa2970-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa3000-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa3030-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa3060-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa3090-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa3120-Slovenia.html',
'https://www.tripadvisor.com/Attractions-g274862-Activities-oa3150-Slovenia.html'
]
def parse(self, response):
for link in response.css('.EsZYd a::attr(href)').getall():
yield response.follow(link, callback=self.parse_categories)
def parse_categories(self, response):
yield {
'name': response.css('h1.WlYyy.cPsXC.GeSzT::text').get(),
'reviews': response.xpath('(//*[#class="cfIVb"])[1]//text()').getall(),
'address': response.xpath('(//*[#class="dGWve"])//text()').getall(),
'url': response.url,
}
It's not really related to python, but css-selectors.
CSS classes should separate with dot and not space WlYyy.cPsXC.GeSzT.
Best suggestion would be to use chrome with dev-toolbar. It will give you an ability to get path to the specific element via css-selector or xpath, just right-click on the element in a DOM-tree and select copy menu-item.
Avoid using classes (especially one without semantic meaning) as an anchor point. They might change from page to page, or in time.
Better to use semantically meaningful nodes, like in your case:
XPath for the title would looks like this //main//header//div[#data-automation="main_h1"]//h1.
You can't use for loop in each listing page
from scrapy.crawler import CrawlerProcess
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'https://www.tripadvisor.com/Attractions-g187427-Activities-oa90-Spain'
]
def parse(self, response):
for link in response.css('.EsZYd a::attr(href)').getall():
#print(link)
yield response.follow(link, callback=self.parse_categories)
def parse_categories(self, response):
yield {
'name' : response.css('h1.WlYyy.cPsXC.GeSzT::text').get(),
'address' :''.join(response.xpath('(//*[#class="hxQKk"])[1]//text()').getall()[:-1]),
'url':response.url
}
if __name__ == "__main__":
process =CrawlerProcess(QuotesSpider)
process.crawl()
process.start()
Related
How to scrape description of every link
After i useed scrapy in python and i have all url links of my products from one site, how can i acces every link and scrape description of every product? This is my code: import scrapy class aldi2(scrapy.Spider): name = 'aldi2' start_urls = ['https://www.aldi.nl/producten/brood-bakkerij/dagvers-brood.html'] def parse(self,response): for products in response.css('div.mod.mod-article-tile.mod-article-tile--default.ct-backwaren'): yield{ 'name':products.css('span.mod-article-tile__title::text').get().replace('\n','').replace('\t',''), 'price':products.css('span.price__wrapper::text').get().replace('\n','').replace('\t',''), 'unit' :products.css('span.price__unit::text').get().replace('\n',''), 'link' : products.css ('a.mod-article-tile__action').attrib['href'] }
You can use 'response.follow' or 'scrapy.Request' (but you'll need to add the base url) with the desired url. (I changed the 'replace' function with 'strip'). import scrapy class aldi2(scrapy.Spider): name = 'aldi2' start_urls = ['https://www.aldi.nl/producten/brood-bakkerij/dagvers-brood.html'] def parse(self, response): for products in response.css('div.mod.mod-article-tile.mod-article-tile--default.ct-backwaren'): yield{ 'name':products.css('span.mod-article-tile__title::text').get().strip(), 'price':products.css('span.price__wrapper::text').get().strip(), 'unit':products.css('span.price__unit::text').get().strip(), 'link': products.css('a.mod-article-tile__action').attrib['href'] } url = products.css('a.mod-article-tile__action').attrib['href'] yield response.follow(url=url, callback=self.parse_page) def parse_page(self, response): pass
Scrapy problems with crawling specific TAG
I am having a problem with my scrapy program, I want to crawl information from following website https://parts.cat.com/AjaxCATPartLookupResultsView?catalogId=10051&langId=-1&requestType=1&storeId=21801&serialNumber=KSN00190&keyword=&link=> I want to get the "Part No." information inside the "span id=resPartNum" TAG. I have already tried: - NAME_SELECTOR = './/*[#id="resPartNum"]/text()' - NAME_SELECTOR = './/span[#class="resPartNum"]/text() - NAME_SELECTOR = './/tr/td/span[#class="resPartNum"]/a/text()' Here is my full CODE: import scrapy class PartSpider(scrapy.Spider): name = 'part_spider' start_urls = ['https://parts.cat.com/AjaxCATPartLookupResultsView?catalogId=10051&langId=-1&requestType=1&storeId=21801&serialNumber=KSN00190&keyword=&link='] def parse(self, response): SET_SELECTOR = '.set' for part in response.css(SET_SELECTOR): NAME_SELECTOR = './/*[#id="resPartNum"]/text()' yield { 'name': part.css(NAME_SELECTOR).extract_first(), } I am not very advanced in scrapy and would appreciate ANY HELP!!
Use the css selector table.partlookup_table to collect the table item through loop partNum and partName.here extract() return list. import scrapy class PartSpider(scrapy.Spider): name = 'part_spider' start_urls = ['https://parts.cat.com/AjaxCATPartLookupResultsView?catalogId=10051&langId=-1&requestType=1&storeId=21801&serialNumber=KSN00190&keyword=&link='] def parse(self, response): SET_SELECTOR = 'table.partlookup_table' for part in response.css(SET_SELECTOR): #NAME_SELECTOR = './/*[#id="resPartNum"]/text()' yield { 'name': part.css('span.resPartName a::text').extract(), 'partnumber': part.css('span.resPartNum a::text').extract() } process = CrawlerProcess() process.crawl(PartSpider) process.start()
How to scrape on two different domain using scrapy?
Hi I would like to scrape 2 different domain in my script I have tried my if statement but I it seems that it is not working, any idea please? Here's my code class SalesitemSpiderSpider(scrapy.Spider): name = 'salesitem_spider' allowed_domains = ['www2.hm.com'] start_urls = [ 'https://www2.hm.com/en_us/sale/shopbyproductladies/view-all.html?sort=stock&image-size=small&image=stillLife&offset=0&page-size=9999', 'https://www.forever21.com/us/shop/catalog/category/f21/sale', ] def parse_start_url(response): if (response.url == 'https://www2.hm.com/en_us/sale/shopbyproductladies/view-all.html?sort=stock&image-size=small&image=stillLife&offset=0&page-size=9999'): parse_1(response) if (response.url == 'https://www.forever21.com/us/shop/catalog/category/f21/sale'): parse_2(response) def parse_1(self, response): for product_item in response.css('li.product-item'): item = { 'title': product_item.css('h3.item-heading a.link::text').extract_first(), 'regular-price': product_item.css('strong.item-price span.price.regular::text').extract_first(), 'sale-price': product_item.css('strong.item-price span.price.sale::text').extract_first(), 'photo-url': product_item.css('.image-container img::attr(data-src)').extract_first(), 'description-url': "https://www2.hm.com/" + product_item.css('h3.item-heading a::attr(href)').extract_first(), } yield item def parse_2(self, response): #Some code getting item on domain 2 Please Help thank you
Check your allowed_domains variable. You should add new domain, like ['www2.hm.com', 'forever21.com'] or remove it at all. Also you have no parse function. I can suppose to remove your start_urls with if and use start_requests instead. Your code will be more readable. import scrapy class SalesitemSpiderSpider(scrapy.Spider): name = 'salesitem_spider' allowed_domains = ['www2.hm.com', 'forever21.com'] def start_requests(self): urls = ( (self.parse_1, 'https://www2.hm.com/en_us/sale/shopbyproductladies/view-all.html?sort=stock&image-size=small&image=stillLife&offset=0&page-size=9999'), (self.parse_2, 'https://www.forever21.com/us/shop/catalog/category/f21/sale'), ) for cb, url in urls: yield scrapy.Request(url, callback=cb) def parse_1(self, response): print 111111111 def parse_2(self, response): print 2222222222
Use scrapy to get list of urls, and then scrape content inside those urls
I need a Scrapy spider to scrape the following page (https://www.phidgets.com/?tier=1&catid=64&pcid=57) for each URL (30 products, so 30 urls) and then go into each product via that url and scrape the data inside. I have the second part working exactly as I want: import scrapy class ProductsSpider(scrapy.Spider): name = "products" start_urls = [ 'https://www.phidgets.com/?tier=1&catid=64&pcid=57', ] def parse(self, response): for info in response.css('div.ph-product-container'): yield { 'product_name': info.css('h2.ph-product-name::text').extract_first(), 'product_image': info.css('div.ph-product-img-ctn a').xpath('#href').extract(), 'sku': info.css('span.ph-pid').xpath('#prod-sku').extract_first(), 'short_description': info.css('div.ph-product-summary::text').extract_first(), 'price': info.css('h2.ph-product-price > span.price::text').extract_first(), 'long_description': info.css('div#product_tab_1').extract_first(), 'specs': info.css('div#product_tab_2').extract_first(), } # next_page = response.css('div.ph-summary-entry-ctn a::attr("href")').extract_first() # if next_page is not None: # yield response.follow(next_page, self.parse) But I don't know how to do the first part. As you will see I have the main page (https://www.phidgets.com/?tier=1&catid=64&pcid=57) set as the start_url. But how do I get it to populate the start_urls list with all 30 urls I need crawled?
I am not able to test at this moment, so please let me know if this works for you so I can edit it should there be any bugs. The idea here is that we find every link in the first page and yield new scrapy requests passing your product parsing method as a callback import scrapy from urllib.parse import urljoin class ProductsSpider(scrapy.Spider): name = "products" start_urls = [ 'https://www.phidgets.com/?tier=1&catid=64&pcid=57', ] def parse(self, response): products = response.xpath("//*[contains(#class, 'ph-summary-entry-ctn')]/a/#href").extract() for p in products: url = urljoin(response.url, p) yield scrapy.Request(url, callback=self.parse_product) def parse_product(self, response): for info in response.css('div.ph-product-container'): yield { 'product_name': info.css('h2.ph-product-name::text').extract_first(), 'product_image': info.css('div.ph-product-img-ctn a').xpath('#href').extract(), 'sku': info.css('span.ph-pid').xpath('#prod-sku').extract_first(), 'short_description': info.css('div.ph-product-summary::text').extract_first(), 'price': info.css('h2.ph-product-price > span.price::text').extract_first(), 'long_description': info.css('div#product_tab_1').extract_first(), 'specs': info.css('div#product_tab_2').extract_first(), }
How to crawl data from the linked webpages on a webpage we are crawling
I am crawling the names of the colleges on this webpage, but, i also want to crawl the number of faculties in these colleges which is available if open the specific webpages of the colleges by clicking the name of the college. What should i append to this code to get the result. The result should be in the form of [(name1, faculty1), (name2,faculty2),... ] import scrapy class QuotesSpider(scrapy.Spider): name = "student" start_urls = [ 'http://www.engineering.careers360.com/colleges/list-of-engineering-colleges-in-karnataka?sort_filter=alpha', ] def parse(self, response): for students in response.css('li.search-result'): yield { 'name': students.css('div.title a::text').extract(), }
import scrapy class QuotesSpider(scrapy.Spider): name = "student" start_urls = [ 'http://www.engineering.careers360.com/colleges/list-of-engineering-colleges-in-karnataka?sort_filter=alpha', ] def parse(self, response): for students in response.css('li.search-result'): req = scrapy.Request(students.css(SELECT_URL), callback=self.parse_student) req.meta['name'] = students.css('div.title a::text').extract() yield req def parse_student(self, response): yield { 'name': response.meta.get('name') 'other data': response.css(SELECTOR) } Should be something like this. So you send the name of the student in the meta data of the request. That allows you to request it in your next request. If the data is also available on the last page you scrape in parse_student you might want to consider not sending it in the meta data but just to scrape it from the last page.