2017-02-16 23 views
0

Я создаю скребок для гигиены пищевых продуктов. Я дошел до того, что могу успешно получить имя и адреса всех ресторанов на основе того, какой почтовый индекс вводится пользователем. Я попытался получить значение рейтинга гигиены питания, которое будет отображаться для результата .Python (BeautifulSoup) - для Loop возвращает все результаты для одного div, вместо ожидаемого значения

Это значение сохраняется следующим образом на веб-странице:

<div class="rating-image" style="clear: right;"> 
       <a href="/business/abbey-community-college-newtownabbey-antrim-992915.html" title="View Details"> 
        <img src="https://images.scoresonthedoors.org.uk//schemes/735/on_small.png" alt="5 (Very Good)"> 
       </a> 
      </div> 

Я пытаюсь извлечь текст IMG Alt

Мой код находится ниже:

import requests 
import time 
from bs4 import BeautifulSoup 


class RestaurantScraper(object): 

def __init__(self, pc): 
    self.pc = pc  # the input postcode 
    self.max_page = self.find_max_page()  # The number of page available 
    self.restaurants = list()  # the final list of restaurants where the scrape data will at the end of process 

def run(self): 
    for url in self.generate_pages_to_scrape(): 
     restaurants_from_url = self.scrape_page(url) 
     self.restaurants += restaurants_from_url  # we increment the restaurants to the global restaurants list 

def create_url(self): 
    """ 
    Create a core url to scrape 
    :return: A url without pagination (= page 1) 
    """ 
    return "https://www.scoresonthedoors.org.uk/search.php?name=&address=&postcode=" + self.pc + \ 
      "&distance=1&search.x=8&search.y=6&gbt_id=0&award_score=&award_range=gt" 

def create_paginated_url(self, page_number): 
    """ 
    Create a paginated url 
    :param page_number: pagination (integer) 
    :return: A url paginated 
    """ 
    return self.create_url() + "&page={}".format(str(page_number)) 

def find_max_page(self): 
    """ 
    Function to find the number of pages for a specific search. 
    :return: The number of pages (integer) 
    """ 
    time.sleep(5) 
    r = requests.get(self.create_url()) 
    soup = BeautifulSoup(r.content, "lxml") 
    pagination_soup = soup.findAll("div", {"id": "paginator"}) 
    pagination = pagination_soup[0] 
    page_text = pagination("p")[0].text 
    return int(page_text.replace('Page 1 of ', '')) 

def generate_pages_to_scrape(self): 
    """ 
    Generate all the paginated url using the max_page attribute previously scraped. 
    :return: List of urls 
    """ 
    return [self.create_paginated_url(page_number) for page_number in range(1, self.max_page + 1)] 

def scrape_page(self, url): 
    """ 
    This is coming from your original code snippet. This probably need a bit of work, but you get the idea. 
    :param url: Url to scrape and get data from. 
    :return: 
    """ 
    time.sleep(5) 
    r = requests.get(url) 
    soup = BeautifulSoup(r.content, "lxml") 
    g_data = soup.findAll("div", {"class": "search-result"}) 
    ratings = soup.select('div.rating-image img[alt]') 
    restaurants = list() 
    for item in g_data: 
     name = print (item.find_all("a", {"class": "name"})[0].text) 
     restaurants.append(name) 
     try: 
      print (item.find_all("span", {"class": "address"})[0].text) 
     except: 
      pass 
     for rating in ratings: 
      bleh = rating['alt'] 
      print (bleh) 
    return restaurants 


if __name__ == '__main__': 
pc = input('Give your post code') 
scraper = RestaurantScraper(pc) 
scraper.run() 
print ("{} restaurants scraped".format(str(len(scraper.restaurants)))) 

Путь Я попытался собрать каждый рейтинг гигиены для каждого ресторана, используя петлю для обработки, как показано ниже:

for rating in ratings: 
      bleh = rating['alt'] 
      print (bleh) 

Проблема заключается в том, что при запуске скрипта под названием и адресом каждого ресторана он отображает все оценки гигиены питания для всех ресторанов на странице, тогда как мне нужен каждый рейтинг, который будет отображаться под каждым синглом ресторан

Incorrect output of all ratings being displayed

Я имею в виду, что это может быть неправильное положение для цикла?

Большое спасибо всем, кто смотрит на это, и к любому, кто предоставляет руководство

ответ

1

получил эту работу, кажется, забыл добавить цикл для оценок попробовать, за исключением блока. После добавления его в этот блок отображаются одинаковые рейтинги для каждого ресторана.

Ниже полностью рабочий код

import requests 
import time 
from bs4 import BeautifulSoup 


class RestaurantScraper(object): 

def __init__(self, pc): 
    self.pc = pc  # the input postcode 
    self.max_page = self.find_max_page()  # The number of page available 
    self.restaurants = list()  # the final list of restaurants where the scrape data will at the end of process 

def run(self): 
    for url in self.generate_pages_to_scrape(): 
     restaurants_from_url = self.scrape_page(url) 
     self.restaurants += restaurants_from_url  # we increment the restaurants to the global restaurants list 

def create_url(self): 
    """ 
    Create a core url to scrape 
    :return: A url without pagination (= page 1) 
    """ 
    return "https://www.scoresonthedoors.org.uk/search.php?name=&address=&postcode=" + self.pc + \ 
      "&distance=1&search.x=8&search.y=6&gbt_id=0&award_score=&award_range=gt" 

def create_paginated_url(self, page_number): 
    """ 
    Create a paginated url 
    :param page_number: pagination (integer) 
    :return: A url paginated 
    """ 
    return self.create_url() + "&page={}".format(str(page_number)) 

def find_max_page(self): 
    """ 
    Function to find the number of pages for a specific search. 
    :return: The number of pages (integer) 
    """ 
    time.sleep(5) 
    r = requests.get(self.create_url()) 
    soup = BeautifulSoup(r.content, "lxml") 
    pagination_soup = soup.findAll("div", {"id": "paginator"}) 
    pagination = pagination_soup[0] 
    page_text = pagination("p")[0].text 
    return int(page_text.replace('Page 1 of ', '')) 

def generate_pages_to_scrape(self): 
    """ 
    Generate all the paginated url using the max_page attribute previously scraped. 
    :return: List of urls 
    """ 
    return [self.create_paginated_url(page_number) for page_number in range(1, self.max_page + 1)] 

def scrape_page(self, url): 
    """ 
    This is coming from your original code snippet. This probably need a bit of work, but you get the idea. 
    :param url: Url to scrape and get data from. 
    :return: 
    """ 
    time.sleep(5) 
    r = requests.get(url) 
    soup = BeautifulSoup(r.content, "lxml") 
    g_data = soup.findAll("div", {"class": "search-result"}) 
    ratings = soup.select('div.rating-image img[alt]') 
    restaurants = list() 
    for item in g_data: 
     name = print (item.find_all("a", {"class": "name"})[0].text) 
     restaurants.append(name) 
     try: 
      print (item.find_all("span", {"class": "address"})[0].text) 
     except: 
      pass 
     try: 
      for rating in ratings: 
       bleh = rating['alt'] 
       print (bleh)[0].text 
     except: 
      pass 
    return restaurants 


if __name__ == '__main__': 
pc = input('Give your post code') 
scraper = RestaurantScraper(pc) 
scraper.run() 
print ("{} restaurants scraped".format(str(len(scraper.restaurants)))) 

Часть, которая решена проблема заключалась в следующем:

try: 
     for rating in ratings: 
      bleh = rating['alt'] 
      print (bleh)[0].text 
    except: 
     pass 
return restaurants