2017-02-15 1 views
0

J'ai fait un grattoir simple en utilisant Beautiful Soup pour obtenir la note d'hygiène alimentaire des restaurants en fonction du code postal saisi par l'utilisateur. Le code fonctionne correctement et prend les résultats de l'URL correctement.Python - Afficher les résultats de toutes les pages et pas seulement la première page (Belle soupe)

Ce dont j'ai besoin d'aide, c'est comment afficher tous les résultats, pas seulement les résultats de la première page.

Mon code est ci-dessous:

import requests 
from bs4 import BeautifulSoup 

pc = input("Please enter postcode") 

url = "https://www.scoresonthedoors.org.uk/search.php?name=&address=&postcode="+pc+"&distance=1&search.x=8&search.y=6&gbt_id=0&award_score=&award_range=gt" 
r = requests.get(url) 

soup = BeautifulSoup(r.content, "lxml") 
g_data = soup.findAll("div", {"class": "search-result"}) 

for item in g_data: 
    print (item.find_all("a", {"class": "name"})[0].text) 
try: 
    print (item.find_all("span", {"class": "address"})[0].text) 
except: 
    pass 
try: 
    print (item.find_all("div", {"class": "rating-image"})[0].text) 
except: 
    pass 

J'ai découvert en regardant l'URL que la page affichée dépend d'une variable dans la chaîne URL appelée la page

https://www.scoresonthedoors.org.uk/search.php?award_sort=ALPHA&name=&address=BT147AL&x=0&y=0&page=2#results 

Le code de pagination pour le bouton Next Page est:

<a style="float: right" href="?award_sort=ALPHA&amp;name=&amp;address=BT147AL&amp;x=0&amp;y=0&amp;page=3#results" rel="next " title="Go forward one page">Next <i class="fa fa-arrow-right fa-3"></i></a> 

Y at-il un moyen de trouver mon code h Combien de pages de résultats sont présentées, puis récupérez les résultats de chacune de ces pages? La meilleure solution serait d'avoir du code qui change la chaîne d'URL pour changer "page =" chaque fois (par exemple une boucle for) ou est-il un moyen de trouver une solution en utilisant les informations dans le code de lien de pagination ?

Un grand merci pour tous ceux qui fournit de l'aide ou se penche sur cette question

Répondre

1

Vous allez effectivement la bonne façon. Générer les URL paginées pour gratter à l'avance est une bonne approche.

En fait, j'ai presque écrit le code entier. Ce que vous voulez regarder est la fonction find_max_page() d'abord qui consiste à prendre la page max de la chaîne de pagination. Avec ce numéro, vous pouvez alors générer toutes les URL dont vous avez besoin pour gratter et les racler une à une.

Vérifiez le code ci-dessous, il est à peu près tous là.

import requests 
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) 
     """ 
     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: 
     """ 
     r = requests.get(url) 
     soup = BeautifulSoup(r.content, "lxml") 
     g_data = soup.findAll("div", {"class": "search-result"}) 

     restaurants = list() 
     for item in g_data: 
      name = item.find_all("a", {"class": "name"})[0].text 
      restaurants.append(name) 
      try: 
       print item.find_all("span", {"class": "address"})[0].text 
      except: 
       pass 
      try: 
       print item.find_all("div", {"class": "rating-image"})[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))) 
+0

La fonction scrape_page est votre code d'origine. Il pourrait utiliser un peu de travail. Assurez-vous simplement que cette fonction est bien construite. Tout le reste est à peu près prêt. Des questions sur ce code, faites le moi savoir. –

+0

Merci Philippe, Ce code fonctionne parfaitement. –