Как кодировать для l oop in Python для веб-скребка - PullRequest
2 голосов
/ 01 февраля 2020

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

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

Например, если есть только 4 страницы списков, и я прошу его скачать списки на странице 5, веб-URL автоматически изменится на страницу 1, и бот загрузит все списки на странице 1, затем он будет повторять этот процесс для следующих страниц вплоть до страницы 100. Очевидно, я не Мне не нужно 96 повторений автомобилей на странице 1 в моем наборе данных, поэтому я хотел бы перейти к следующей модели автомобиля, когда это произойдет, но я пока не нашел способа сделать это.

Вот что я получил до сих пор:

for x in range(1, 101):
    makes = ["ABARTH", "AC", "AIXAM", "ARIEL", "ASTON%20MARTIN", "AUDI"]
    for make in makes:
        my_url_page_x_make_i = 'https://www.autotrader.co.uk/car-search?' + 'sort=distance' + '&postcode=BS247EY' + '&radius=300' + '&onesearchad=Used&onesearchad=Nearly%20New&onesearchad=New' + '&make=' + make + '&page=' + str(x)
        uClient = uReq(my_url_page_x_make_i)
        page_html = uClient.read()
        uClient.close()
        page_soup = soup(page_html, "html.parser")
        listings = page_soup.findAll("li", {"class": "search-page__result"})
        for listing in listings:
            information_container = listing.find("div", {"class": "information-container"})
            title_container = information_container.find("a", {
                "class": "js-click-handler listing-fpa-link tracking-standard-link"})
            title = title_container.text
            price = listing.find("div", {"class": "vehicle-price"}).text

            print("title: " + title)
            print("price: " + price)

            f.write(title.replace(",", "") + "," + price.replace(",", "") + "\n")
            if len(listings) < 13: makes.remove(make)

f.close()

Это далеко от законченного сценария, и у меня есть только около 1 недели реального Python опыта кодирования.

1 Ответ

1 голос
/ 01 февраля 2020

Я думаю, что я решил вашу проблему, но я бы посоветовал вам инвертировать ваши циклы: l oop on делает до l oop на страницах. Сохраняя исходную реализацию, я решил проблему, вычистив номера страниц внизу страницы, чтобы вы могли остановиться, когда у вас закончатся страницы. Я также исправил BeautifulSoup.findAll в BeautifulSoup.find_all, потому что, если вы используете BeautifulSoup версии 4, этот метод устарел

# please show your imports
from urllib.request import urlopen
from bs4 import BeautifulSoup
# I assume you imported BeautifulSoup as soup and urlopen as uReq


# I assume you opened a file object
with open('output.txt', 'w') as f:
    # for the aston martin, if you want this to be scalable, escape url invalid
    # chars using urllib.parse.quote()
    makes = ["ABARTH", "AC", "AIXAM", "ARIEL", "ASTON%20MARTIN", "AUDI"]
    # make it clear what variables are
    for page in range(1, 101):  # here I tested it with 9 pages for speed sake
        for make in makes:
            # don't overcomplicate variable names; here I believe that an f-string would be appropriate
            req_url = f"https://www.autotrader.co.uk/car-search?sort=distance&" \
                      f"postcode=BS247EY&radius=300&onesearchad=Used&onesearchad=Nearly%20New&" \
                      f"onesearchad=New&make={make}&page={page}"
            req = urlopen(req_url)
            page_html = req.read()
            req.close()
            page_soup = BeautifulSoup(page_html, "html.parser")
            # BeautifulSoup.findAll is deprecated use find_all instead
            listings = page_soup.find_all("li", {"class": "search-page__result"})
            for listing in listings:
                information_container = listing.find("div", {"class": "information-container"})
                title_container = information_container.find("a", {
                    "class": "js-click-handler listing-fpa-link tracking-standard-link"})
                title = title_container.text
                price = listing.find("div", {"class": "vehicle-price"}).text
                print("make:", make)
                print("title:", title)
                print("price:", price)
                f.write(title.replace(",", "") + "," + price.replace(",", "") + "\n")
            # Solving your issue
            # we take the page numbers from the bottom of the page and take the last
            # actually here it's the last but one (-2) because the last element would
            # be the arrow.
            pagination = page_soup.find_all('li', {'class': 'pagination--li'})[-2]
            # convert it to int and compare it to the current page
            # if it's less than or equal to the current page, remove
            # the make from the list.
            if int(pagination.text) <= page:
                makes.remove(make)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...