【问题标题】:Get content loaded dynamically on mouseclick using Scrapy Splash and Lua使用 Scrapy Splash 和 Lua 在鼠标点击时动态加载内容
【发布时间】:2021-03-30 11:03:03
【问题描述】:

我有一个带有 Lua 脚本的 Scrapy Splash 刮板。 Lua 脚本目前仅在页面上启动滚动以在搜索页面上加载更多结果。 从搜索页面我导航到我抓取的详细信息页面。 但是,在详细信息页面上,照片轮播尚未出现在 DOM 中,它会在用户单击 #showphotos 元素时动态加载。

单击该元素后,将加载以下照片轮播 HTML:

<div id="slider">
    <div class="slider-inner">
        <div class="item active">
            <img src="https://www.example.com/images/1.jpg">
        </div>
        <div class="item">
            <img src="https://www.example.com/images/2.jpg">
        </div>
    </div>
</div>

我已经检查了herehere

所以我尝试编写一些脚本:

click_script = """
        function main(splash, args)

            btn = splash:select_all('#showphotos')[0]
            btn:mouse_click()
            assert(splash:wait(0.5))
              return {
                num = #splash:select_all('#slider div.slider-inner'),
                html = splash:html()
              }
        end
        """

由于我是 Splash 和 Lua 的新手,我不知道在哪里添加此代码或从哪里调用它。

我创建了一个测试详细信息页面here

我当前的代码:

myscraper.py

import json
import re

import scrapy
import time
from scrapy_splash import SplashRequest
from scrapy.selector import Selector
from scrapy.http import HtmlResponse
from myresults.items import MyResultItem


class Spider(scrapy.Spider):
    name = 'myscraper'
    allowed_domains = ['example.com']
    start_urls = ['https://www.example.com/results']

    def start_requests(self):
        # lua script for scroll to bottom while all objects appeared
        lua_script = """
        function main(splash, args)
          local object_count = 0
          local url = splash.args.url
          splash:go(url)
          splash:wait(0.5)
          local get_object_count = splash:jsfunc([[
            function (){
              var objects = document.getElementsByClassName("object-adres");
              return objects.length;
            }
            ]])
          temp_object_count = get_object_count()
          local retry = 3
          while object_count ~= temp_object_count do
            splash:evaljs('window.scrollTo(0, document.body.scrollHeight);')
            splash:wait(0.5)
            object_count = temp_object_count
            temp_object_count = get_object_count()
            
          end
          return splash:html()
        end
        """

        # yield first splash request with lua script and parse it from parse def
        yield SplashRequest(
            self.start_urls[0], self.parse,
            endpoint='execute',
            args={'lua_source': lua_script},
        )

    def parse(self, response):
        # get all properties from first page which was generated with lua script
        # get all adreslink from a tag
        object_links = response.css('a.adreslink::attr(href)').getall()
        for link in object_links:
            # send request with each link and parse it from parse_object def
            yield scrapy.Request(link, self.parse_object)

    def parse_object(self, response):
        # create new MyResultItem which will saved to json file
        item = MyResultItem()

        item['url'] = response.url # get url        
        


        yield item

items.py

import scrapy

class RentalItem(scrapy.Item):
    id = scrapy.Field()
    photos = scrapy.Field()
    url = scrapy.Field()

    pass

【问题讨论】:

    标签: python lua scrapy mouseclick-event dynamic-content


    【解决方案1】:

    Lua 脚本像 Python 脚本一样运行。在Spider -&gt; start_requests -&gt; lua_script 中,您已经有一个 Lua 脚本。您要选择第一个#showphotos 元素并单击它;此外,您还想在结果中添加更多数据。

    因此,在执行已经存在的 Lua 代码之后,我们想告诉 Splash 选择第一个 #showphotos 元素:

    btn = splash:select_all('#showphotos')[1]
    

    请注意索引 1,而不是 0,因为 splash:select_all 数组从 1 开始。

    之后,点击它:

    btn:mouse_click()
    

    最后,在结果中添加更多数据:

    return {
        num = splash:select_all('#slider div.slider-inner')[1].node.outerHTML,
        html = splash:html()
    }
    

    再次,请注意索引 1,而不是 0,因为 splash:select_all 数组从 1 开始。另外,我添加了 .node.outerHTML,因为 splash:select_all() 返回一个 Lua 对象,并且没有默认的方式将其序列化为 JSON (ref)

    最后,你应该得到这样的结果:

    function main(splash, args)
      local object_count = 0
      local url = splash.args.url
      splash:go(url)
      splash:wait(0.5)
    
      local get_object_count = splash:jsfunc([[
        function (){
          var objects = document.getElementsByClassName("object-adres");
          return objects.length;
        }
      ]])
      temp_object_count = get_object_count()
      local retry = 3
      while object_count ~= temp_object_count do
        splash:evaljs('window.scrollTo(0, document.body.scrollHeight);')
        splash:wait(0.5)
        object_count = temp_object_count
        temp_object_count = get_object_count()
      end
    
      btn = splash:select_all('#showphotos')[1]
      btn:mouse_click()
      assert(splash:wait(0.5))
      
      return {
        num = splash:select_all('#slider div.slider-inner')[1].node.outerHTML,
        html = splash:html()
      }
    end
    

    【讨论】:

    • 太棒了,谢谢!我会试试的。我在您的解决方案中还不明白的是 Lua 脚本的第一部分与搜索概述页面相关,例如/allcompanies 向下滚动以显示所有结果。 Lua 脚本的第二部分以及您建议的在#showphotos 元素上单击鼠标的代码仅与具有照片轮播的详细信息页面相关,例如:company/1443/apple,company/8233/msft,company/1413/google。如果我按照现在的建议将所有内容包装在一个函数 function main(splash, args) 中,我会不必要地多次执行脚本吗?
    • ps。我还更新了我的测试示例页面以显示我的意思
    猜你喜欢
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-16
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    相关资源
    最近更新 更多