J'ai écrit un script en python pour gratter tous les names et les links associés à partir de la page de destination d'un site Web en utilisant la fonction .get_links(). Ensuite, j'ai créé une autre fonction .get_info() pour atteindre une autre page (en utilisant les liens dérivés de la première fonction) afin de gratter les numéros de téléphone à partir de là.

Je n'avais pas du tout besoin de créer la deuxième fonction si mon objectif était d'analyser les deux éléments de cette page Web car ils sont déjà disponibles dans la page de destination.

Cependant, la façon dont je voudrais que mon analyseur se comporte est d'imprimer le names (report de la première fonction) dans la deuxième fonction avec le phone numbers là-bas. Plus important encore, je ne veux pas supprimer le for loop défini dans la deuxième fonction. Si for loop n'était pas dans la deuxième fonction, le problème ne se serait pas posé. Sans utiliser for loop, je peux déjà obtenir la sortie souhaitée.

Voici mon script jusqu'à présent:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

url = "https://potguide.com/alaska/marijuana-dispensaries/"

def get_links(link):
    session = requests.Session()
    session.headers['User-Agent'] = 'Mozilla/5.0'
    r = session.get(link)
    soup = BeautifulSoup(r.text,"lxml")
    for items in soup.select("#StateStores .basic-listing"):
        name = items.select_one("h4 a").text
        namelink = urljoin(link,items.select_one("h4 a").get("href"))  ##making it a fully qualified url
        get_info(session,name,namelink)          ##passing session in order to reuse it

def get_info(session,title,url):
    r = session.get(url)
    soup = BeautifulSoup(r.text,"lxml")
    for items in soup.select("ul.list-unstyled"):  ##if I did not use for loop I could get the output as desired.
        try:
            phone = items.select_one("a[href^='tel:']").text
        except:
            phone = ""
        print(title,phone)

if __name__ == '__main__':
    get_links(url)

La sortie que j'ai:

AK Frost 
AK Frost 
AK Frost 
AK Frost 
AK Frost 
AK Frost (907) 563-9333
AK Frost 
AK Frost 
AK Frost (907) 563-9333
AK Frost  
AK Fuzzy Budz 
AK Fuzzy Budz (907) 644-2838
AK Fuzzy Budz 
AK Fuzzy Budz 
AK Fuzzy Budz (907) 644-2838

Ma sortie attendue:

AK Frost (907) 563-9333
AK Fuzzy Budz (907) 644-2838
8
SIM 23 mai 2018 à 18:38

4 réponses

Meilleure réponse

Je pense que la sélection de ul.list-unstyled dans la sous-page est trop large, il y en a trop avec du contenu que vous ne voulez pas vraiment.

Si vous ne voulez vraiment que les numéros de téléphone, vous pouvez rechercher directement les balises a où le href commence par "tel:". Le problème est toujours que ces sites listent plusieurs numéros de cette façon, généralement 2, où l'un d'eux n'est pas visible. Celui qui est visible semble toujours être en dessous de div.col-md-3. J'ai essayé ceci:

def get_info(session,title,url):
    r = session.get(url)
    soup = BeautifulSoup(r.text,"lxml")
    for a_phone in soup.select("div.col-md-3 a[href^='tel:']"):        
        print(title, a_phone.text)

Et a obtenu le résultat suivant:

AK Frost (907) 563-9333
AK Fuzzy Budz (907) 644-2838
AK Joint (907) 522-5222
AK Slow Burn (907) 868-1450
Alaska Fireweed (907) 258-9333
Alaskabuds (907) 334-6420
Alaskan Leaf (907) 770-0262
Alaska's Green Light District (907) 644-2839
AM Delight (907) 229-1730
Arctic Herbery (907) 222-1466
Cannabaska (907) 375-9333
Catalyst Cannabis Company (907) 344-0668
Dankorage (907) 279-3265
Enlighten Alaska (907) 290-8559
Great Northern Cannabis (907) 929-9333
Hillside Natural Wellness (907) 868-8639
Hollyweed 907 (907) 929-3331
Raspberry Roots (907) 522-2450
Satori (907) 222-5420
The House of Green (907) 929-3105
Uncle Herb's (907) 561-4372
The Green Spot (907) 354-7044
Denali's Cannabis Cache (907) 683-2633
GOOD (907) 452-5463
Goodsinse (907) 347-7689
Grass Station 49 (907) 374-4420
Green Life Supply (907) 374-4769
One Hit Wonder (844) 420-1448
Pakalolo Supply Company (907) 479-9000
Rebel Roots (907) 455-4055
True Dank (907) 451-4516
The Herbal Cache (907) 783-0420
Denali 420 Recreationals (907) 892-9333
Glacier Valley Shoppe (907) 419-7943
Green Elephant (907) 290-8400
Rainforest Farms (907) 209-2670
The Fireweed Factory (907) 957-2670
Red Run Cannabis Company (907) 283-0800
Cannabis Corner (907) 225-4420
Rainforest Cannabis (907) 247-9333
The Stoney Moose (907) 617-8973
Chena Cannabis (907) 488-0489
The 420 (907) 772-3673
Green Leaf (907) 623-0332
Weed Dudes (907) 623-0605
Remedy Shoppe (907) 983-3345
Fat Tops (907) 953-2470
High Bush Buds (907) 953-9393
Pine Street Cannabis Company (907) 260-3330
Permafrost Distributors (907) 260-7584
Hilltop Premium Green (907) 745-4425
The High Expedition Company (907) 733-0911
Herbal Outfitters (907) 835-4201
Bad Gramm3r (907) 357-0420
Green Degree (907) 376-3155
Green Jar (907) 631-3800
Rosebuds Shatter House (907) 376-9334
Happy Cannabis (907) 305-0292
3
Jeronimo 27 mai 2018 à 18:05

À mon avis, vous devriez utiliser le dictionnaire javascript sous-jacent qui contient déjà vos données (et bien plus) dans un format structuré.

Vous pouvez utiliser yaml pour convertir le dictionnaire javascript en objet Python dict. Vous pouvez facilement accéder à partir de vos champs de dictionnaire tels que id, name, city, address, city, state, etc.

Voici un exemple de travail:

import json, re, requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import yaml

url = "https://potguide.com/alaska/marijuana-dispensaries/"

def get_links(link):
    session = requests.Session()
    session.headers['User-Agent'] = 'Mozilla/5.0'
    r = session.get(link)
    soup = BeautifulSoup(r.text,"lxml")
    for items in soup.select("#StateStores .basic-listing"):
        name = items.select_one("h4 a").text
        namelink = urljoin(link,items.select_one("h4 a").get("href"))
        get_info(session, name, namelink)

def get_info(session, title, url):    
    response = requests.get(url)
    soup = BeautifulSoup(response.content, "lxml")
    script = next((i for i in map(str, soup.find_all("script", type="text/javascript"))
                   if 'mapOptions' in i), None)
    if script:
        js_dict = script.split('__mapOptions = ')[1].split(';\n')[0]
        d = yaml.load(js_dict)
        print(title, d['mapStore']['phone'])

get_links(url)

Résultat:

AK Frost (907) 563-9333
AK Fuzzy Budz (907) 644-2838
AK Joint (907) 522-5222
AK Slow Burn (907) 868-1450
Alaska Fireweed (907) 258-9333
...
Bad Gramm3r (907) 357-0420
Green Degree (907) 376-3155
Green Jar (907) 631-3800
Rosebuds Shatter House (907) 376-9334
Happy Cannabis (907) 305-0292
4
jpp 27 mai 2018 à 20:23

Vous avez déjà obtenu suffisamment de bonnes réponses, mais vous pouvez également essayer ceci:

def get_info(session,title,url):
    r = session.get(url)
    soup = BeautifulSoup(r.text,"lxml")
    for items in soup.select("ul.list-unstyled"):
        if len(items.select("a[href^='tel:']")):
            phone = items.select("a[href^='tel:']")[0].text
            break
        else:
            phone = "N/A"
    print(title, phone)

Ou avec une sorte de doublure :)

def get_info(session,title,url):
    r = session.get(url)
    soup = BeautifulSoup(r.text,"lxml")
    phone = ([items.select("a[href^='tel:']")[0].text for items in soup.select("ul.list-unstyled") 
              if len(items.select("a[href^='tel:']"))] + ["N/A"])[0]
    print(title, phone) 

Notez que "N/A" est attribué si aucun numéro de téléphone n'est trouvé (par exemple Northern Lights Indoor Gardens N/A)

3
Andersson 29 mai 2018 à 19:51

Si l'objectif est uniquement d'obtenir la sortie attendue, cela devrait fonctionner:

def get_info(session,title,url):
    r = session.get(url)
    soup = BeautifulSoup(r.text,"lxml")
    for items in soup.select("ul.list-unstyled"):
        try:
           phone = items.select_one("a[href^='tel:']").text
        except:
           # skip item and continue
           continue  
        else:
           # exception wasn't rised, you have the phone
           print(title,phone)
           break
6
Artem Nepo 25 mai 2018 à 19:31