Веб-очистка с помощью веб-драйвера Selenium, первая итерация пропущена - PullRequest
0 голосов
/ 29 октября 2018

Я пытаюсь очистить сайт Копарта от Selenium. Данные представлены в строках, которые включают заголовок. Я использую этот раздел кода, чтобы сначала получить HTML-код всей страницы.

from bs4 import BeautifulSoup as soup
import requests
from selenium import webdriver

filename = "coparttest.csv"
f = open(filename, "w", encoding="utf-8")
headers = "lotnumber,makeyear,makebrand,model,location,sale_date,odometer,doc_type,damage,est_retail_value,current_bid,photos\n"
f.write(headers)

chrome_driver = "/Users/nguyenquanghung/Desktop/webscrape/silenium/chromedriver"
driver = webdriver.Chrome(chrome_driver)

url = "https://www.copart.com/vehicleFinderSearch/?displayStr=BMW,%5B2014%20TO%202019%5D&from=%2FvehicleFinder%2F%3Fintcmp%3Dweb_homepage_hero_vehiclefinder_en&searchStr=%7B%22MISC%22:%5B%22%23MakeCode:BMW%20OR%20%23MakeDesc:BMW%22,%22%23VehicleTypeCode:VEHTYPE_V%22,%22%23LotYear:%5B2014%20TO%202019%5D%22%5D,%22sortByZip%22:false,%22buyerEnteredZip%22:null%7D"
driver.get(url)

page = driver.execute_script("return document.documentElement.outerHTML")
page_soup = soup(page, "html.parser")
rows = page_soup.findAll("tr",{"role":"row"})

Затем я запускаю цикл for, чтобы получить все необходимые данные, включая фотографии каждой строки, которые появляются только при нажатии на кнопку масштабирования. Поэтому я использую driver.find_element_by_xpath(...).click() нажмите на кнопку переписки, чтобы открыть карусель фотографий, а затем снова получите HTML-код: driver. execute_script("return document.documentElement.outerHTML") чтобы наконец получить фотографии. Обратите внимание, что я также пропускаю первую строку, так как это заголовок. Код работает просто отлично. ЗА ИСКЛЮЧЕНИЕМ, в первом ряду нет фотографий, первые фото прикрепляются ко второму ряду и т. Д. Кажется, что внутренний цикл for пропускает первую итерацию. Вот остаток кода:

for index, row in enumerate(rows[1:]):
    lotnumber = row.find("div",{"class":""}).a.text
    makeyear = row.find("span",{"data-uname":"lotsearchLotcenturyyear"}).text
    makebrand = row.find("span",{"data-uname":"lotsearchLotmake"}).text
    model = row.find("span",{"data-uname":"lotsearchLotmodel"}).text
    location = row.find("span",{"data-uname":"lotsearchLotyardname"}).text
    sale_date = row.find("span",{"data-uname":"lotsearchLotauctiondate"}).text
    odometer = row.find("span",{"data-uname":"lotsearchLotodometerreading"}).text.replace(",","")
    doc_type = row.find("span",{"data-uname":"lotsearchSaletitletype"}).text
    damage = row.find("span",{"data-uname":"lotsearchLotdamagedescription"}).text
    est_retail_value = row.find("span",{"data-uname":"lotsearchLotestimatedretailvalue"}).text.replace(",","")

    bid = row.findAll("ul",{"class":"list-unstyled"})[0]
    bid_span = bid.li.ul.li.findAll("span")
    current_bid = bid_span[1].text.replace(",","")

    #Get photo
    #zoom photo
    zoom_button = str(index + 1)
    driver.find_element_by_xpath('//*[@id="serverSideDataTable"]/tbody/tr[' + zoom_button + ']/td[2]/div[1]/span').click()
    photo_html = driver.execute_script("return document.documentElement.outerHTML")
    photo_soup = soup(photo_html, "html.parser")
    # print("photo_soup ---> ",photo_soup)
    photos_list = photo_soup.findAll("img",{"class":"zoomImg"})
    photos = [index]
    for photo in photos_list:
        src = photo["src"]
        photos.append(src)
        print("print photo ---> ",index, src)
    photos = str(photos).replace(","," |")
    #close photo
    driver.find_element_by_xpath('//*[@id="lotImage"]/div/div/div[1]/h4/button').click()

    print("print row ---> ",index,zoom_button,lotnumber,makeyear,makebrand,model,location,sale_date,odometer,doc_type,damage,est_retail_value,current_bid,photos)

    #write row to csv
    f.write(lotnumber+","+makeyear+","+makebrand+","+model+","+location+","+sale_date+","+odometer+","+doc_type+","+damage+","+est_retail_value+","+current_bid+","+photos+"\n")


driver.close()
f.close()       

Кто-нибудь знает, почему знают, как / почему первая строка получает пустые данные?

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

@ sers Наконец-то я нашел способ обойти это. Я должен открыть и закрыть зоомбутон один раз, прежде чем он получит какие-либо данные для первого ряда. Понятия не имею почему. Но, спасибо, я изучил WebDriverWait и EC. Вот что у меня есть:

zoom_button = str(index + 1)

Open and close for the first time:

driver.find_element_by_xpath('//*[@id="serverSideDataTable"]/tbody/tr[' + zoom_button + ']/td[2]/div[1]/span').click()
photos_list = driver.execute_script("return [...document.querySelectorAll('.zoomImg')].map(e=>e.getAttribute('src'))")
driver.implicitly_wait(10)
driver.find_element_by_xpath('//*[@id="lotImage"]/div/div/div[1]/h4/button').click()

Open it again and get data:

driver.find_element_by_xpath('//*[@id="serverSideDataTable"]/tbody/tr[' + zoom_button + ']/td[2]/div[1]/span').click()
photos_list = driver.execute_script("return [...document.querySelectorAll('.zoomImg')].map(e=>e.getAttribute('src'))")
photos = []
for photo in photos_list:
    photos.append(photo)
    print("print photo ---> ", photo)
photos = str(photos)
driver.implicitly_wait(10)
driver.find_element_by_xpath('//*[@id="lotImage"]/div/div/div[1]/h4/button').click()
print("print row ---> ",index,zoom_button,lotnumber,makeyear,makebrand,model,location,sale_date,odometer,doc_type,damage,est_retail_value,current_bid,photos)
0 голосов
/ 29 октября 2018

Попробуйте заменить код:

photo_html = driver.execute_script("return document.documentElement.outerHTML")
photo_soup = soup(photo_html, "html.parser")
# print("photo_soup ---> ",photo_soup)
photos_list = photo_soup.findAll("img",{"class":"zoomImg"})
photos = [index]
for photo in photos_list:
    src = photo["src"]
    photos.append(src)
    print("print photo ---> ",index, src)
photos = str(photos).replace(","," |")

с:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

#...

driver.find_element_by_xpath('//*[@id="serverSideDataTable"]/tbody/tr[' + zoom_button + ']/td[2]/div[1]/span').click()
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".zoomImg")))
photos_list = driver.execute_script("return [...document.querySelectorAll('.zoomImg')].map(e=>e.getAttribute('src'))")
for photo in photos_list:
  print("print photo ---> ", photo)

У вас проблема с индексом кнопки зума zoom_button = str(index + 1), кнопка зума должна быть zoom_button = str(index)

Рабочий код Java:

WebDriverWait wait = new WebDriverWait(driver, 20);

driver.get("https://www.copart.com/vehicleFinderSearch/?displayStr=BMW,%5B2014%20TO%202019%5D&from=%2FvehicleFinder%2F%3Fintcmp%3Dweb_homepage_hero_vehiclefinder_en&searchStr=%7B%22MISC%22:%5B%22%23MakeCode:BMW%20OR%20%23MakeDesc:BMW%22,%22%23VehicleTypeCode:VEHTYPE_V%22,%22%23LotYear:%5B2014%20TO%202019%5D%22%5D,%22sortByZip%22:false,%22buyerEnteredZip%22:null%7D");

List<WebElement> rows = wait.until(ExpectedConditions.numberOfElementsToBe(By.cssSelector("tbody tr[role=row]"), 21));
for (WebElement row:rows) {
    row.findElement(By.cssSelector("span.searchiconbtn")).click();
    ArrayList<String> photos = (ArrayList)((JavascriptExecutor) driver).executeScript("return [...document.querySelectorAll('.zoomImg')].map(e=>e.getAttribute('src'))");
}
...