Веб-очистка нескольких похожих страниц - PullRequest
2 голосов
/ 12 апреля 2020

Я новичок в python просмотре веб-страниц, и я пытался взять адреса различных локаций winmar в Канаде, а также поместить результаты в файл CSV. До сих пор я обнаружил, что единственный способ различать сайты в разных местах - это код в конце адреса (числа). Проблема заключается в том, что результаты не меняются при запуске программы, а вместо этого выдают результаты первого расположения (305) при печати в файл csv. Спасибо за ваше время и внимание!

Вот мой код:

import csv
import requests
from bs4 import BeautifulSoup

x = 0
numbers = ['305', '405', '306', '307', '308', '309', '4273']

f = csv.writer(open('Winmar_locations.csv', 'w'))
f.writerow(['City:', 'Address:'])

for links in numbers:

    for x in range(0, 6):
        url = 'https://www.winmar.ca/find-a-location/' + str(numbers[x])
        r = requests.get(url)
        soup = BeautifulSoup(r.content, "html.parser")

    location_name = soup.find("div", attrs={"class": "title_block"})
    location_name_items = location_name.find_all('h2')

    location_list = soup.find(class_='quick_info')
    location_list_items = location_list.find_all('p')

    for name in location_name_items:
        names = name.text
        names = names.replace('Location | ', '')

    for location in location_list_items:
        locations = location.text.strip()
        locations = locations.replace('24 Hour Emergency | (902) 679-1116','')

    print(names, locations)
    x = x+1

    f.writerow([names, locations])

Ответы [ 2 ]

2 голосов
/ 12 апреля 2020

В вашем коде несколько ошибок, и одна вещь о веб-сайте, который вы просматриваете

  • Первый доступ к URL-адресу, подобному этому https://www.winmar.ca/find-a-location/308, не изменит местоположение должным образом, это должно быть примерно таким: https://www.winmar.ca/find-a-location/#308 с хэш-бангом перед числом.

  • На сайте есть дубликат html с одинаковыми классами, это означает, что у вас почти все места загружены все время и они просто выбирают, что показывать, из их js кода - плохой практики конечно-, что заставляет вашего сопоставителя всегда получать одно и то же местоположение, что объясняет, почему вы всегда повторяли одно и то же местоположение.

  • Наконец, у вас было много ненужных циклов, вам нужно всего лишь l oop над массивом чисел и все.

вот модифицированная версия вашего кода

import csv
import requests
from bs4 import BeautifulSoup

x = 0
numbers = ['305', '405', '306', '307', '308', '309', '4273']


names = []
locations = []
for x in range(0, 6):
    url = 'https://www.winmar.ca/find-a-location/#' + str(numbers[x])
    print(f"pinging url {url}")

    r = requests.get(url)
    soup = BeautifulSoup(r.content, "html.parser")
    scope = soup.find(attrs={"data-id": str(numbers[x])})

    location_name = scope.find("div", attrs={"class": "title_block"})
    location_name_items = location_name.find_all('h2')


    location_list = scope.find(class_='quick_info')
    location_list_items = location_list.find_all('p')

    name = location_name.find_all("h2")[0].text
    print(name)

    names.append(name)

    for location in location_list_items:
        loc = location.text.strip()
        if '24 Hour Emergency' in loc: 
            continue
        print(loc)
        locations.append(loc)

    x = x+1

Обратите внимание на область действия, которую я сделал

    scope = soup.find(attrs={"data-id": str(numbers[x])})

, которая делает ваш код невосприимчивым к тому, сколько мест они загрузили в html, вы ориентируетесь только на область с местоположением, которое вы выбрали. нт.

это приводит к:

pinging url https://www.winmar.ca/find-a-location/#305
Location | Annapolis
70 Donald E Hiltz Connector Road
Kentville, NS
B4N 3V7
pinging url https://www.winmar.ca/find-a-location/#405
Location | Bridgewater
15585 Highway # 3
Hebbville, NS
B4V 6X7
pinging url https://www.winmar.ca/find-a-location/#306
Location | Halifax
9 Isnor Dr
Dartmouth, NS
B3B 1M1
pinging url https://www.winmar.ca/find-a-location/#307
Location | New Glasgow
5074 Hwy. #4, RR #1
Westville, NS
B0K 2A0
pinging url https://www.winmar.ca/find-a-location/#308
Location | Port Hawkesbury
8 Industrial Park Rd
Lennox Passage, NS
B0E 1V0
pinging url https://www.winmar.ca/find-a-location/#309
Location | Sydney
358 Keltic Drive
Sydney River, NS
B1R 1V7

1 голос
/ 12 апреля 2020

Хотя у вас есть квалифицированный ответ, я подумал придумать мой. Я постарался сделать сценарий лаконичным, избавляясь от многословия. Убедитесь, что ваша версия bs4 4.7.0 или более поздняя, ​​чтобы она поддерживала псевдо-селектор , который я определил в скрипте для определения адреса.

import csv
import requests
from bs4 import BeautifulSoup

base = 'https://www.winmar.ca/find-a-location/#{}'

numbers = ['305', '405', '306', '307', '308', '309', '4273']

with open("Winmar_locations.csv","w",newline="") as f:
    writer = csv.writer(f)
    writer.writerow(['City','Address'])

    while numbers:
        num = numbers.pop(0)
        r = requests.get(base.format(num))
        soup = BeautifulSoup(r.content,"html.parser")

        location_name = soup.select_one(f"[data-id='{num}'] .title_block > h2.title").contents[-1]
        location_address = soup.select_one(f"[data-id='{num}'] .heading:contains('Address') + p").get_text(strip=True)
        writer.writerow([location_name,location_address])
        print(location_name,location_address)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...