Относительные селекторы в Selenium? - PullRequest
0 голосов
/ 27 июня 2018

Мне интересно, есть ли в Selenium «относительные» селекторы, такие как селектор ele.css в Scrapy. Например, в Scrapy вы можете сделать это:

for li in response.css('ul.rows li p.result-info'):
    lnk = li.css('a::attr(href)').extract_first()
    prc = li.css('span.result-meta span.result-price::text').extract_first()
    sqf = li.css('span.result-meta span.housing::text').extract_first()
    loc = li.css('span.result-meta span.result-hood::text').extract_first()
    objct = {
        'lnk': lnk,
        'prc': prc,
    }
    if sqf:
        chunk = sqf.split()
        objct['sqf'] = chunk[len(chunk)-1]
    if loc:
        objct['loc'] = loc
    yield objct

Возможно ли сделать что-то подобное в Selenium?

Сейчас я использую следующий код, который, очевидно, создает проблемы, поскольку пути не имеют значения. Вместо того, чтобы соскабливать, скажем, все детали для каждого предмета по одному предмету за раз (т.е. цена, размер, цвет для предмета A, затем цена, размер, цвет для предмета B, затем цена, размер, цвет для предмета C, так что и так далее) я застрял? очистка одной детали для всех элементов (то есть цены для элемента A, элемента B и элемента C, затем размера для элемента A, элемента B, элемента C), как показано в следующем коде.

discoverable_cards = browser.find_elements(By.XPATH, '//div[@class="discoverableCard"]')
product_type = browser.find_elements(By.XPATH, '//div[@class="discoverableCard-body"]/div[1]/span')
titles = browser.find_elements(By.XPATH, '//div[contains(@class, "discoverableCard-title")]')
descriptions = browser.find_elements(By.XPATH, '//div[contains(@class, "discoverableCard-description")]')
categories = browser.find_elements(By.XPATH, '//div[contains(@class, "discoverableCard-category")]')
balances = browser.find_elements(By.XPATH, '//div[contains(@class, "discoverableCard-balance")]')
currencies = browser.find_elements(By.XPATH, '//div[contains(@class, "discoverableCard-currencyCode")]')
percentages = browser.find_elements(By.XPATH, '//div[contains(@class, "discoverableCard-percent")]')
statuses = browser.find_elements(By.XPATH, '//span[contains(@class, "discoverableCard-formattedDate")] | //div[contains(@class, "discoverableCard-InDemandBottomLabel")]')

Образец HTML (и пример того, что я имею в виду)

<discoverable-card ng-repeat="campaign in campaigns track by campaign.clickthroughUrl" ng-click="cardClick()" gogo-test="card_1" lazy-load-image="true" discoverable="campaign" iggref="pica" class="ng-scope ng-isolate-scope"><div class="discoverableCard">
  <a in-view="$inview &amp;&amp; trackImpression()" ng-click="clickDiscoverable($event)" href="/projects/tastetro-spice-system-vegan/coming_soon/pica" gogo-test="card">
    <div class="discoverableCard-image lazyloaded" ng-class="{'lazyload': lazyLoadImage}" id="discoverableCard-image" data-bgset="https://c1.iggcdn.com/indiegogo-media-prod-cld/image/upload/c_fill,f_auto,h_273,w_273/cvuilsvvspmvmxhdynup.jpg" style="background-image: url(&quot;https://c1.iggcdn.com/indiegogo-media-prod-cld/image/upload/c_fill,f_auto,h_273,w_273/cvuilsvvspmvmxhdynup.jpg&quot;);">
    <picture style="display: none;"><source data-srcset="https://c1.iggcdn.com/indiegogo-media-prod-cld/image/upload/c_fill,f_auto,h_273,w_273/cvuilsvvspmvmxhdynup.jpg" sizes="273px" srcset="https://c1.iggcdn.com/indiegogo-media-prod-cld/image/upload/c_fill,f_auto,h_273,w_273/cvuilsvvspmvmxhdynup.jpg"><img alt="" class="lazyautosizes lazyloaded" data-sizes="auto" data-parent-fit="cover" sizes="273px"></picture></div>
    <div class="discoverableCard-body">
      <!-- ngIf: viewModel.isCampaign() --><div ng-if="viewModel.isCampaign()" class="discoverableCard-type discoverableCard-type--crowdfunding ng-scope">
           <span class="discoverableCard-type--crowdfundingLabel ng-binding" ng-bind="i18n.t('discoverable_card.type_label_campaign')">Funding</span>
           <!-- ngIf: !user && viewModel.isSaveForLaterCompatible() --><div user-auth-modal="" ng-if="!user &amp;&amp; viewModel.isSaveForLaterCompatible()" ng-click="toggleSavedForLater($event)" banner="i18n.t('discoverable_card.auth_modal_banner')" class="ng-scope ng-isolate-scope"><span class="campaignLoginModal" ng-click="openModal()" ng-transclude="">
             <span class="iggPopoverHtml ng-binding ng-scope ng-isolate-scope" ng-class="{ 'entreTooltip' : entre }" ng-bind-html="trustedHtml" igg-popover="" placement="top" aria-label="Save for later" role="img" aria-disabled="false" html="<svg><use xlink:href='#icon-icon-follow'></use></svg>"><svg><use xlink:href="#icon-icon-follow"></use></svg></span>
           </span><user-auth-modal banner="banner" status="status" class="ng-isolate-scope"></user-auth-modal></div><!-- end ngIf: !user && viewModel.isSaveForLaterCompatible() -->
           <!-- ngIf: user && viewModel.isSaveForLaterCompatible() && !viewModel.isSavedForLater() -->
           <!-- ngIf: user && viewModel.isSaveForLaterCompatible() && viewModel.isSavedForLater() -->
      </div><!-- end ngIf: viewModel.isCampaign() -->
      <!-- ngIf: viewModel.isProduct() -->
      <!-- ngIf: viewModel.isOffering() -->
      <div class="discoverableCard-title ng-binding discoverableCard-lineClamp2" ng-class="::viewModel.titleClampClass()" gogo-test="title" ng-bind="::viewModel.discoverable.title">TasteTro Spice System</div>
      <div class="discoverableCard-description ng-binding discoverableCard-lineClamp3" ng-class="viewModel.descriptionClampClass()" ng-bind="::viewModel.discoverable.tagline">An intelligent spice rack that delivers mouthwatering spice blends at the touch of a button.</div>
      <!-- ngIf: viewModel.isOffering() -->
      <div class="discoverableCard-category ng-binding" gogo-test="category" ng-click="clickCategory($event)" ng-bind="::viewModel.discoverable.category">Food &amp; Beverages</div>
      <!-- ngIf: viewModel.showCrowdFundingProgress() -->
      <!-- ngIf: viewModel.isStandardCampaign() -->
      <!-- ngIf: viewModel.isInDemandCampaign() -->
      <!-- ngIf: viewModel.isPreLaunchCampaign() --><div ng-if="viewModel.isPreLaunchCampaign()" class="discoverableCard-preLaunchBulletPoint ng-binding ng-scope" ng-bind="::viewModel.discoverable.bulletPoint">Register to get access to TasteTro's secret perks!</div><!-- end ngIf: viewModel.isPreLaunchCampaign() -->
      <!-- ngIf: viewModel.isPreLaunchCampaign() --><div ng-if="viewModel.isPreLaunchCampaign()" class="discoverableCard-LaunchingSoon ng-scope">
        <svg-icon icon="icon-rocket" class="ng-isolate-scope"><svg class="iconLaunchingRocket" aria-label="Rocket Icon" role="img" aria-disabled="false">
  <use xlink:href="#icon-rocket"></use>
</svg>
</svg-icon>
        <span class="discoverableCard-LaunchingSoonLabel ng-binding" ng-bind="::i18n.t('discoverable_card.launching_soon_label')">Launching Soon</span>
      </div><!-- end ngIf: viewModel.isPreLaunchCampaign() -->
      <!-- ngIf: viewModel.isProduct() -->
      <!-- ngIf: viewModel.isOffering() -->
    </div>
    <!-- ngIf: viewModel.isOffering() -->
  </a>
</div>
</discoverable-card>

В приведенном выше примере я хотел бы, скажем, выбрать discoverable-card (т. Е. discoverable_card = browser.find_elements(By.XPATH, '//discoverable-card'), а затем сделать следующий выбор следующим образом: dc_child = discoverable_card.find_elements(By.XPATH, 'relative/path/to/child').

1 Ответ

0 голосов
/ 27 июня 2018

Вы можете просто выбрать дочерний / дочерний элемент уже определенного элемента, как показано ниже:

discoverable_cards = browser.find_elements(By.XPATH, '//discoverable-card')
for card in discoverable_cards:
    dc_child = card.find_element(By.XPATH, './relative/path/to/child')

Обратите внимание, что вы должны указывать точку в начале дочернего (./) / потомка (.//) локатора, чтобы указывать на текущий card элемент

...