使用Python和selenium从网站高效下载图像

时间:2018-01-22 13:29:59

标签: python selenium web-scraping

免责声明:我没有任何网页抓取/ HTML / javascripts / css等相关背景,但我知道一些Python。

我的最终目标是使用相关标签下载ShapeNet网站中每3515次汽车视图的所有第4张图片视图。 enter image description here 例如,3515对中的第一对将是可以在此图片右侧的折叠菜单中找到的图像:(可以通过单击第一页的第一项然后单击图像来加载){{3在第一张图片(左上角的第一辆车)中可以看到相关的标签“运动实用程序”。

为此,我在@DebanjanB的帮助下编写了一段代码,点击第一张图片上的运动实用程序,打开iframe点击图片,然后下载第4张图片enter image description here。完整的工作代码就是这个:

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

profile = webdriver.FirefoxProfile()
profile.set_preference("network.proxy.type", 1)
profile.set_preference("network.proxy.socks", "yourproxy")
profile.set_preference("network.proxy.socks_port", yourport)
#browser = webdriver.Firefox(firefox_profile=profile)
browser = webdriver.Firefox()

browser.get('https://www.shapenet.org/taxonomy-viewer')
#Page is long to load
wait = WebDriverWait(browser, 30)
element = wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id='02958343_anchor']")))
linkElem = browser.find_element_by_xpath("//*[@id='02958343_anchor']")
linkElem.click()
#Page is also long to display iframe
element = wait.until(EC.element_to_be_clickable((By.ID, "model_3dw_bcf0b18a19bce6d91ad107790a9e2d51")))
linkElem = browser.find_element_by_id("model_3dw_bcf0b18a19bce6d91ad107790a9e2d51")
linkElem.click()
#iframe slow to be displayed
wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'viewerIframe')))
#iframe = browser.find_elements_by_id('viewerIframe')
#browser.switch_to_frame(iframe[0])
element = wait.until(EC.element_to_be_clickable((By.XPATH, "/html/body/div[3]/div[3]/h4")))
time.sleep(10)
linkElem = browser.find_element_by_xpath("/html/body/div[3]/div[3]/h4")
linkElem.click()



img = browser.find_element_by_xpath("/html/body/div[3]/div[3]//div[@class='searchResult' and @id='image.3dw.bcf0b18a19bce6d91ad107790a9e2d51.3']/img[@class='enlarge']")
src = img.get_attribute('src')


os.system("wget %s --no-check-certificate"%src)

这有几个问题。首先,我需要手动了解每个模型的xpath model_3dw_ bcf0b18a19bce6d91ad107790a9e2d51 我还需要提取它们可以在以下位置找到的标记: link to my question 。所以我需要通过检查显示的每个图像来提取它。然后我需要切换页面(有22页),甚至可以向下滚动每页以确保我拥有一切。其次,我不得不使用time.sleep两次,因为基于等待可点击的另一种方法似乎并不像预期的那样工作。

我有两个问题,第一个显而易见的是正确的处理方式吗?我觉得即使没有time.sleep这可能会非常快,这感觉非常像人类会做的事情,因此如果它确实是要走的路,那么其次必须非常低效:我怎么能写一个双循环on页面和项目能够有效地提取标签和模型ID吗?

编辑1:似乎:

l=browser.find_elements_by_xpath("//div[starts-with(@id,'model_3dw')]")

可能是迈向完成的第一步

编辑2:几乎没有,但代码中充满了time.sleep。仍然需要获取标签名称并循环遍历页面

编辑3:标签名称仍然需要遍历页面并发布解决方案的初稿

3 个答案:

答案 0 :(得分:1)

因此,让我尝试正确理解您的意思,然后看看我是否可以帮助您解决问题。我不懂Python,所以请原谅我的synthax错误。

您想要点击每个183533汽车,然后下载弹出的iframe中的第4个图像。正确的吗?

现在,如果是这种情况,让我们看看你需要的第一个元素,页面上包含所有汽车的元素。

因此,要获得第1页的所有160辆汽车,您将需要:

elements = browser.find_elements_by_xpath("//img[@class='resultImg lazy']");

这将为您返回160个图像元素。这正是显示图像的数量(第1页)

然后你可以说:

for el in elements:
    {here you place the code you need to download the 4th image, 
     so like switch to iframe, click on the 4th image etc.}

现在,对于第一页,您已经制作了一个循环,它将为其上的每辆车下载第4张图像。

由于您有多个页面,因此这并不能完全解决您的问题。值得庆幸的是,页面导航,上一页和下一页,在第一页和/或最后一页上显示为灰色。

所以你可以说:

browser.find_element_by_xpath("//a[@class='next']").click();

如果元素不可点击,请确保捕获元素将在最后一页显示为灰色。

答案 1 :(得分:1)

您可以考虑检查网页用于查询数据的网址,然后使用Python的“请求”,而不是抓取网站。包直接从服务器发出API请求。我不是网站上的注册用户,因此我无法向您提供任何示例,但描述shapenet.org网站的文章特别提及:

"为了方便地访问所有模型和 - ShapeNet中包含的符号数据,我们构造一个 所有3D模型及其相关注释的索引 使用Apache Solr框架的tions。每个存储的 - 给定3D模型的表示法包含在索引中 作为一个可以轻松查询和过滤的单独属性 通过简单的基于Web的UI。另外,要做到了 数据集方便研究人员访问,我们提供了一个 批量下载功能。"

这表明,只要您可以了解其查询语言提供的内容,通过API执行您想要的操作可能会更容易。在他们的质量保证/论坛中搜索也可能很有效。

答案 2 :(得分:0)

我想出了这个答案,哪种方法有效,但我不知道如何删除多次调用time.sleep我不会接受我的答案,直到有人发现更优雅的东西(当它到达最后时)它失败的最后一页):

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

profile = webdriver.FirefoxProfile()
profile.set_preference("network.proxy.type", 1)
profile.set_preference("network.proxy.socks", "yourproxy")
profile.set_preference("network.proxy.socks_port", yourport)
#browser = webdriver.Firefox(firefox_profile=profile)
browser = webdriver.Firefox()

browser.get('https://www.shapenet.org/taxonomy-viewer')
#Page is long to load
wait = WebDriverWait(browser, 30)
element = wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id='02958343_anchor']")))

linkElem = browser.find_element_by_xpath("//*[@id='02958343_anchor']")
linkElem.click()

tag_names=[]
page_count=0
while True:

    if page_count>0:
        browser.find_element_by_xpath("//a[@class='next']").click()
    time.sleep(2)
    wait.until(EC.presence_of_element_located((By.XPATH, "//div[starts-with(@id,'model_3dw')]")))  
    list_of_items_on_page=browser.find_elements_by_xpath("//div[starts-with(@id,'model_3dw')]")
    list_of_ids=[e.get_attribute("id") for e in list_of_items_on_page]

    for i,item in enumerate(list_of_items_on_page):
    #Page is also long to display iframe
        current_id=list_of_ids[i]
        element = wait.until(EC.element_to_be_clickable((By.ID, current_id)))
        car_image=browser.find_element_by_id(current_id)
        original_tag_name=car_image.find_element_by_xpath("./div[@style='text-align: center']").get_attribute("innerHTML")

        count=0
        tag_name=original_tag_name
        while tag_name in tag_names:            
            tag_name=original_tag_name+"_"+str(count)
            count+=1

        tag_names.append(tag_name)



        car_image.click()


        wait.until(EC.frame_to_be_available_and_switch_to_it((By.ID, 'viewerIframe')))

        element = wait.until(EC.element_to_be_clickable((By.XPATH, "/html/body/div[3]/div[3]/h4")))
        time.sleep(10)
        linkElem = browser.find_element_by_xpath("/html/body/div[3]/div[3]/h4")
        linkElem.click()

        img = browser.find_element_by_xpath("/html/body/div[3]/div[3]//div[@class='searchResult' and @id='image.3dw.%s.3']/img[@class='enlarge']"%current_id.split("_")[2])
        src = img.get_attribute('src')
        os.system("wget %s --no-check-certificate -O %s.png"%(src,tag_name))
        browser.switch_to.default_content()
        browser.find_element_by_css_selector(".btn-danger").click()
        time.sleep(1)

    page_count+=1

也可以从selenium导入NoSuchElementException并使用while循环使用try除了去除任意time.sleep。