【问题标题】:Web scraping multiple similar pages网页抓取多个相似页面
【发布时间】:2020-04-12 01:05:50
【问题描述】:

我是 python 网络抓取的新手,我试图获取加拿大不同 winmar 位置的地址,并将结果放入 csv 文件中。到目前为止,我发现区分不同地点的唯一方法是通过地址末尾的代码(数字)。问题是结果不会随着程序的运行而改变,而是在打印到 csv 文件时产生第一个位置 (305) 的结果。感谢您的时间和考虑!

这是我的代码:

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])

【问题讨论】:

    标签: python web-scraping beautifulsoup


    【解决方案1】:

    您的代码中有几处错误,而您正在抓取的网站有一处错误

    • 第一次访问像https://www.winmar.ca/find-a-location/308这样的url不会正确改变位置,它需要像这样https://www.winmar.ca/find-a-location/#308在数字前加上hashbang。

    • 该网站具有相同类的重复 html,这意味着您几乎一直在加载所有位置,他们只是从他们的 js 代码中选择要显示的位置-当然是不好的做法-,这使您的匹配器总是得到相同的位置,这解释了为什么您总是重复相同的位置。

    • 最后,你有很多不必要的循环,你只需要遍历 numbers 数组就可以了。

    这是您的代码的修改版本

    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
    
    

    【讨论】:

    • 非常感谢!我不知道那个网站。感谢您的深入解释,我不知道该感谢您多少!祝你有美好的一天。
    【解决方案2】:

    虽然你有一个合格的答案,但我还是想出我的。我试图使脚本简洁,摆脱冗长。确保您的 bs4 版本为 4.7.0 或更高版本,以便它支持我在脚本中定义的pseudo selector 以定位地址。

    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)
    

    【讨论】:

    • 非常感谢您的解决方案,当我有机会时,我一定会尝试两者(我在移动 atm 上)。谢谢你,祝你有美好的一天!
    猜你喜欢
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 2016-08-09
    • 2022-01-21
    • 2021-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多