javascript स्क्रैप+स्प्लैश रिटर्न एचटीएमएल का प्रयोग करें




python web-scraping (2)

मैं स्क्रेपी और स्पलैश को निकालने की कोशिश कर रहा हूं। एक अभ्यास के रूप में, मैंने निम्नलिखित जावास्क्रिप्ट भारी वेबसाइट पर बटन पर छपने का प्रयास करने की कोशिश की: http://thestlbrowns.com/ और फिर नए गाया पृष्ठ के एचटीएमएल वापस लौटें।

मेरा कोड इस तरह दिखता है:

import scrapy
import json
from scrapy import Request
class MySpider(scrapy.Spider):
    name = 'spiderman'
    domain = ['web']
    start_urls = ['http://thestlbrowns.com/']

    def start_requests(self):
        script = """
         function main(splash)
             local url = splash.args.url
             assert(splash:go(url))
             assert(splash:wait(1))

             assert(splash:runjs("$('#title.play-ball > a:first-child').click()"))
             assert(splash:wait(1))

             -- return result as a JSON object
             return {
                 html = splash:html(),
                 -- we don't need screenshot or network activity
                 --png = splash:png(),
                 --har = splash:har(),
             }
         end
        """

        for url in self.start_urls:
            yield Request(url, self.parse, meta={'splash': {'args':{'lua_source': script},'endpoint':'execute',}})

    def parse(self, response):
        splash_json = json.loads(response.body_as_unicode())

हालांकि जब मैं इस कोड को चलाता हूं, तो मुझे निम्न आउटपुट मिलता है:

$ scrapy crawl spiderman
2017-01-12 14:19:03 [scrapy.utils.log] INFO: Scrapy 1.3.0 started (bot: myScrapingProject)
2017-01-12 14:19:03 [scrapy.utils.log] INFO: Overridden settings: {'BOT_NAME': 'myScrapingProject', 'DOWNLOAD_DELAY': 0.25, 'DUPEFILTER_CLASS': 'scrapy_splash.SplashAwareDupeFilter', 'HTTPCACHE_STORAGE': 'scrapy_splash.SplashAwareFSCacheStorage', 'NEWSPIDER_MODULE': 'myScrapingProject.spiders', 'SPIDER_MODULES': ['myScrapingProject.spiders'], 'USER_AGENT': 'Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.7'}
2017-01-12 14:19:03 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.logstats.LogStats']
2017-01-12 14:19:03 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy_splash.SplashCookiesMiddleware',
 'scrapy_splash.SplashMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2017-01-12 14:19:03 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy_splash.SplashDeduplicateArgsMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2017-01-12 14:19:03 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2017-01-12 14:19:03 [scrapy.core.engine] INFO: Spider opened
2017-01-12 14:19:03 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2017-01-12 14:19:03 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2017-01-12 14:19:16 [scrapy_splash.middleware] WARNING: Bad request to Splash: {'error': 400, 'info': {'error': "bad argument #2 to 'assert' (string expected, got table)", 'line_number': 8, 'source': '[string "..."]', 'message': 'Lua error: [string "..."]:8: bad argument #2 to \'assert\' (string expected, got table)', 'type': 'LUA_ERROR'}, 'description': 'Error happened while executing Lua script', 'type': 'ScriptError'}
2017-01-12 14:19:16 [scrapy.core.engine] DEBUG: Crawled (400) <POST http://localhost:8050/execute> (referer: None)
2017-01-12 14:19:16 [scrapy.spidermiddlewares.httperror] INFO: Ignoring response <400 http://thestlbrowns.com/>: HTTP status code is not handled or not allowed
2017-01-12 14:19:16 [scrapy.core.engine] INFO: Closing spider (finished)
2017-01-12 14:19:16 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 1222,
 'downloader/request_count': 1,
 'downloader/request_method_count/POST': 1,
 'downloader/response_bytes': 471,
 'downloader/response_count': 1,
 'downloader/response_status_count/400': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2017, 1, 12, 13, 19, 16, 846242),
 'log_count/DEBUG': 2,
 'log_count/INFO': 8,
 'log_count/WARNING': 1,
 'response_received_count': 1,
 'scheduler/dequeued': 2,
 'scheduler/dequeued/memory': 2,
 'scheduler/enqueued': 2,
 'scheduler/enqueued/memory': 2,
 'splash/execute/request_count': 1,
 'splash/execute/response_count/400': 1,
 'start_time': datetime.datetime(2017, 1, 12, 13, 19, 3, 417278)}
2017-01-12 14:19:16 [scrapy.core.engine] INFO: Spider closed (finished)

प्रश्न: क्या कोई इसे ठीक करने के बारे में जानता है / क्या मैं गलत कर रहा हूं?

संपादित करें: जब मैं स्क्रिप्ट को स्प्लिट करने से पहले script = quote(script) जोड़ता हूं, मुझे निम्न त्रुटि आउटपुट मिलता है:

Message: 'Bad request to Splash: {\'type\': \'ScriptError\', \'description\': \'Error happened while executing Lua script\', ' \
         '\'error\': 400, \'info\': {\'error\': "unexpected symbol near \'%\'", \'type\': \'LUA_INIT_ERROR\', \'line_number\': 1, ' \
         '\'source\': \'[string "%0A%20%20%20%20%20%20%20%20%20function%20main..."]\',' \
         ' \'message\': \'[string "%0A%20%20%20%20%20%20%20%20%20function%20main..."]:1: unexpected symbol near \\\'%\\\'\'}}'

स्पलैश प्रतिक्रिया में कुछ संकेत शामिल हैं:

{'description': 'Error happened while executing Lua script',
 'error': 400,
 'info': {'error': "bad argument #2 to 'assert' (string expected, got table)",
          'line_number': 8,
          'message': 'Lua error: [string "..."]:8: bad argument #2 to \'assert\' (string expected, got table)',
          'source': '[string "..."]',
          'type': 'LUA_ERROR'},
 'type': 'ScriptError'}

यदि आप स्प्लैश के वेब इंटरफेस (यह आपका दोस्त है!) में अपनी स्क्रिप्ट की कोशिश करते हैं, तो आपके पास एक ही त्रुटि है, इस रेखा से आ रही है:

assert(splash:runjs("$('#title.play-ball > a:first-child').click()"))

यदि आप उस लिआ स्क्रिप्ट को थोड़ा बदलते हैं, तो त्रुटि को पकड़ते हुए (वैसे, मेरा मानना ​​है कि आपका मतलब है .title.play-ball > a:first-child क्योंकि इसमें id="title" साथ कोई तत्व नहीं है):

function main(splash)
     local url = splash.args.url
     assert(splash:go(url))
     assert(splash:wait(1))

     -- go back 1 month in time and wait a little (1 second)
     ok, err = splash:runjs("$('.title.play-ball > a:first-child').click()")
     assert(splash:wait(1))

     -- return result as a JSON object
     return {
         html = splash:html(),
         error = err
         -- we don't need screenshot or network activity
         --png = splash:png(),
         --har = splash:har(),
     }
 end

और इसे वेब इंटरफेस में चलाना, आपको प्रतिक्रिया में एक "त्रुटि" ऑब्जेक्ट मिलता है, जो दर्शाता है:

error: Object
    js_error: "ReferenceError: Can't find variable: $"
    js_error_message: "Can't find variable: $"
    js_error_type: "ReferenceError"
    message: "JS error: \"ReferenceError: Can't find variable: $\""
    splash_method: "runjs"
    type: "JS_ERROR"

ऐसा लगता है कि $ जादू उस वेबसाइट पर काम नहीं कर रहा है। उदाहरण के लिए, आप इसे क्रोम कंसोल में इस्तेमाल कर सकते हैं, लेकिन स्पलैश के साथ आप शायद / जाहिरा तौर पर jQuery (या कुछ इसी तरह) को लोड करने की ज़रूरत है, splash:autoload साथ splash:autoload आमतौर पर। उदाहरण के लिए:

function main(splash)
     assert(splash:autoload("https://code.jquery.com/jquery-3.1.1.min.js"))
     local url = splash.args.url
     assert(splash:go(url))
     assert(splash:wait(1))

     -- go back 1 month in time and wait a little (1 second)
     ok, err = splash:runjs("$('.title.play-ball > a:first-child').click()")
     assert(splash:wait(1))

     -- return result as a JSON object
     return {
         html = splash:html(),
         error = err
         -- we don't need screenshot or network activity
         --png = splash:png(),
         --har = splash:har(),
     }
 end

ध्यान दें कि यह जावास्क्रिप्ट कोड स्पलैश के साथ मेरे लिए काम नहीं करता (स्क्रीनशॉट "इतिहास" वस्तु नहीं दिखा)।

लेकिन मैंने वेब इंटरफ़ेस में निम्नलिखित के साथ कोशिश की, और मुझे "इतिहास" शो मिला (png स्क्रीनशॉट में - जिसे यहां टिप्पणी किया गया है):

function main(splash)
     -- no need to load jQuery when you use splash:select
     --assert(splash:autoload("https://code.jquery.com/jquery-3.1.1.min.js"))
     local url = splash.args.url
     assert(splash:go(url))
     assert(splash:wait(15))

     local element = splash:select('.title.play-ball > a:first-child')
     local bounds = element:bounds()
     assert(element:mouse_click{x=bounds.width/2, y=bounds.height/2})
     assert(splash:wait(5))

     -- return result as a JSON object
     return {
         html = splash:html(),
         -- we don't need screenshot or network activity
         --png = splash:png(),
         --har = splash:har(),
     }
 end

दरअसल, स्पलैश 2.3 में उस तरह के इंटरैक्शन के लिए सहायक हैं (उदाहरण के लिए किसी तत्व पर क्लिक करना) उदाहरण के लिए छप देखें : चुनें और तत्व: mouse_click

यह भी ध्यान रखें कि मैंने wait() मूल्यों को बढ़ा दिया


स्पलैश को पास करने से पहले आपको अपनी स्क्रिप्ट को "उद्धरण" की आवश्यकता है:

script = """Your script"""
from urllib.parse import quote
script = quote(script)
# 'Your%20script'




splash