สามารถใช้ scrapy เพื่อขูดเนื้อหาแบบไดนามิกจากเว็บไซต์ที่ใช้ AJAX ได้หรือไม่


145

เมื่อเร็ว ๆ นี้ฉันได้เรียนรู้ Python และฉันกำลังจุ่มมือลงในการสร้าง web-scraper มันไม่มีอะไรแฟนซีเลย วัตถุประสงค์เพียงอย่างเดียวคือการลบข้อมูลออกจากเว็บไซต์การเดิมพันและนำข้อมูลนี้ไปไว้ใน Excel

ปัญหาส่วนใหญ่แก้ไขได้และฉันมีความยุ่งเหยิงเล็กน้อย อย่างไรก็ตามฉันกำลังกระโดดข้ามสิ่งกีดขวางขนาดใหญ่ไปหนึ่งประเด็น หากเว็บไซต์โหลดตารางม้าและแสดงรายการราคาการเดิมพันปัจจุบันข้อมูลนี้ไม่ได้อยู่ในไฟล์ต้นฉบับ เบาะแสคือว่าข้อมูลนี้มีการถ่ายทอดสดในบางครั้งโดยมีการอัปเดตตัวเลขจากเซิร์ฟเวอร์ระยะไกลบางแห่งอย่างชัดเจน HTML บนพีซีของฉันมีช่องโหว่ที่เซิร์ฟเวอร์ของพวกเขากำลังผลักดันข้อมูลที่น่าสนใจทั้งหมดที่ฉันต้องการ

ตอนนี้ประสบการณ์ของฉันกับเนื้อหาเว็บแบบไดนามิกอยู่ในระดับต่ำดังนั้นสิ่งนี้เป็นสิ่งที่ฉันมีปัญหาในการหัวของฉัน

ฉันคิดว่า Java หรือ Javascript เป็นกุญแจสำคัญซึ่งจะปรากฏขึ้นบ่อยครั้ง

มีดโกนเป็นเพียงเครื่องมือเปรียบเทียบราคา บางเว็บไซต์มี API แต่ฉันต้องการสิ่งนี้สำหรับเว็บไซต์ที่ไม่มี ฉันใช้ไลบรารี่กับ Python 2.7

ฉันขอโทษถ้าคำถามนี้เปิดกว้างเกินไป ในระยะสั้นคำถามของฉันคือ: จะใช้ scrapy อย่างไรในการขูดข้อมูลไดนามิกนี้เพื่อให้สามารถใช้งานได้? เพื่อที่ฉันสามารถขูดข้อมูลการเดิมพันนี้ในเวลาจริง


1
ฉันจะรับข้อมูลนี้ข้อมูลที่เป็นแบบไดนามิกและอยู่ได้อย่างไร
โจเซฟ

1
หากหน้าของคุณมีจาวาสคริปต์ให้ลองทำเช่นนี้
reclosedev

3
ลองใช้ส่วนFirefoxขยายบางอย่างเช่นhttpFoxหรือliveHttpHeadersโหลดหน้าเว็บที่ใช้คำขอ ajax Scrapy ไม่ได้ระบุคำขอ ajax โดยอัตโนมัติคุณต้องค้นหา URL ajax ที่เหมาะสมด้วยตนเองแล้วทำการร้องขอด้วย
Aamir Adnan

ไชโยฉันจะให้ส่วนขยายของ Firefox เป็นตัวช่วย
Joseph

มีโซลูชั่นโอเพนซอร์ซจำนวนมาก แต่ถ้าคุณกำลังมองหาวิธีที่ง่ายและรวดเร็วในการทำเช่นนี้โดยเฉพาะสำหรับปริมาณงานขนาดใหญ่ให้ตรวจสอบ SnapSearch ( snapsearch.io ) มันถูกสร้างขึ้นสำหรับไซต์ JS, HTML5 และ SPA ที่ต้องการการรวบรวมข้อมูลของเครื่องมือค้นหา ลองตัวอย่าง (ถ้ามีเนื้อหาที่ว่างนั่นหมายความว่าไซต์ไม่มีเนื้อหาเนื้อความซึ่งอาจหมายถึงการเปลี่ยนเส้นทาง 301)
CMCDragonkai

คำตอบ:


74

เบราว์เซอร์ที่ใช้ Webkit (เช่น Google Chrome หรือ Safari) มีเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ในตัว ใน Chrome Menu->Tools->Developer Toolsคุณสามารถเปิดได้ Networkแท็บช่วยให้คุณสามารถดูข้อมูลทั้งหมดเกี่ยวกับทุกคำขอและการตอบสนอง:

ป้อนคำอธิบายรูปภาพที่นี่

ที่ด้านล่างของภาพคุณจะเห็นว่าฉันได้กรองคำขอไปที่XHR- นี่คือคำขอที่ทำโดยรหัสจาวาสคริปต์

เคล็ดลับ: บันทึกจะถูกล้างทุกครั้งที่คุณโหลดหน้าเว็บที่ด้านล่างของรูปภาพปุ่มจุดสีดำจะเก็บบันทึกไว้

หลังจากวิเคราะห์คำขอและคำตอบคุณสามารถจำลองคำขอเหล่านี้จากโปรแกรมรวบรวมข้อมูลเว็บของคุณและดึงข้อมูลที่มีค่า ในหลายกรณีการรับข้อมูลของคุณจะง่ายกว่าการแยกวิเคราะห์ HTML เนื่องจากข้อมูลนั้นไม่มีตรรกะการนำเสนอและมีการจัดรูปแบบเพื่อให้สามารถเข้าถึงได้ด้วยรหัสจาวาสคริปต์

Firefox มีส่วนขยายที่คล้ายกันจะเรียกว่าวางเพลิง บางคนอาจยืนยันว่า firebug นั้นมีประสิทธิภาพมากกว่า แต่ฉันชอบความเรียบง่ายของ webkit


141
นี่เป็นคำตอบที่ได้รับการยอมรับได้อย่างไรถ้าไม่มีคำว่า 'scrapy' อยู่ในนั้น?
ชุดเครื่องมือ

มันใช้งานได้และมันง่ายในการแยกวิเคราะห์โดยใช้โมดูล json ใน python มันเป็นทางออก! เปรียบเทียบกับที่ลองใช้ซีลีเนียมหรือสิ่งอื่น ๆ ที่ผู้คนกำลังบอก หากวิธีการอื่นเป็นวิธีที่ซับซ้อนกว่านี้ฉันก็จะมอบให้คุณ แต่ไม่ใช่กรณีที่นี่ @Toolkit
Arion_Miles

1
สิ่งนี้ไม่เกี่ยวข้องจริงๆ คำถามคือวิธีการใช้อย่างเร็วเพื่อขูดเว็บไซต์แบบไดนามิก
E. Erfan

"วิธีการห่ามนี้เป็นคำตอบที่ได้รับการยอมรับ" - เนื่องจากการใช้งานจริงจะต้องมีความถูกต้องทางการเมือง มนุษย์เข้าใจบริบท
Espresso

98

นี่คือตัวอย่างง่ายๆของ scrapyการร้องขอ AJAX มาดูเว็บไซต์rubin-kazan.ruกันเถอะ

ข้อความทั้งหมดถูกโหลดด้วยคำขอ AJAX เป้าหมายของฉันคือการดึงข้อความเหล่านี้ด้วยคุณสมบัติทั้งหมดของพวกเขา (ผู้เขียน, วันที่, ... ):

ป้อนคำอธิบายรูปภาพที่นี่

เมื่อฉันวิเคราะห์ซอร์สโค้ดของหน้าฉันไม่เห็นข้อความเหล่านี้ทั้งหมดเพราะหน้าเว็บใช้เทคโนโลยี AJAX แต่ฉันสามารถใช้ Firebug จาก Mozilla Firefox (หรือเครื่องมือที่เทียบเท่าในเบราว์เซอร์อื่น) เพื่อวิเคราะห์คำขอ HTTP ที่สร้างข้อความบนหน้าเว็บ:

ป้อนคำอธิบายรูปภาพที่นี่

ไม่โหลดซ้ำทั้งหน้า แต่เฉพาะบางส่วนของหน้าเว็บที่มีข้อความ เพื่อจุดประสงค์นี้ฉันคลิกหมายเลขหน้าโดยพลการที่ด้านล่าง:

ป้อนคำอธิบายรูปภาพที่นี่

และฉันสังเกตการร้องขอ HTTP ที่รับผิดชอบเนื้อหาข้อความ:

ป้อนคำอธิบายรูปภาพที่นี่

หลังจากเสร็จสิ้นฉันวิเคราะห์ส่วนหัวของคำขอ (ฉันต้องอ้างว่า URL นี้ฉันจะแยกจากหน้าแหล่งที่มาจากส่วน var ดูรหัสด้านล่าง):

ป้อนคำอธิบายรูปภาพที่นี่

และเนื้อหาข้อมูลแบบฟอร์มของคำขอ (วิธี HTTP คือ "โพสต์"):

ป้อนคำอธิบายรูปภาพที่นี่

และเนื้อหาของการตอบกลับซึ่งเป็นไฟล์ JSON:

ป้อนคำอธิบายรูปภาพที่นี่

ซึ่งนำเสนอข้อมูลทั้งหมดที่ฉันกำลังมองหา

จากนี้ไปฉันต้องนำความรู้ทั้งหมดนี้ไปใช้ในเรื่องที่สนใจ ให้นิยามแมงมุมเพื่อจุดประสงค์นี้:

class spider(BaseSpider):
    name = 'RubiGuesst'
    start_urls = ['http://www.rubin-kazan.ru/guestbook.html']

    def parse(self, response):
        url_list_gb_messages = re.search(r'url_list_gb_messages="(.*)"', response.body).group(1)
        yield FormRequest('http://www.rubin-kazan.ru' + url_list_gb_messages, callback=self.RubiGuessItem,
                          formdata={'page': str(page + 1), 'uid': ''})

    def RubiGuessItem(self, response):
        json_file = response.body

ในparseฟังก์ชั่นฉันมีการตอบสนองสำหรับคำขอแรก ในRubiGuessItemฉันมีไฟล์ JSON พร้อมข้อมูลทั้งหมด


6
สวัสดี คุณช่วยอธิบายได้ว่า 'url_list_gb_messages' คืออะไร? ฉันไม่เข้าใจ ขอบคุณ
โพลาไรซ์

4
อันนี้ดีกว่าแน่นอน
1a1a11a

1
@polarise รหัสนั้นใช้reโมดูล (นิพจน์ปกติ) มันค้นหาสตริง'url_list_gb_messages="(.*)"'และแยกเนื้อหาของวงเล็บในตัวแปรที่มีชื่อเดียวกัน นี่เป็นคำแนะนำที่ดี: guru99.com/python-regular-expressions-complete-tutorial.html
MGP

42

หลายครั้งที่การรวบรวมข้อมูลเราพบปัญหาที่เนื้อหาที่สร้างการแสดงผลบนหน้าเว็บถูกสร้างขึ้นด้วย Javascript และดังนั้น scrapy จึงไม่สามารถรวบรวมข้อมูลได้ (เช่นคำขอ ajax, jQuery craziness)

อย่างไรก็ตามหากคุณใช้ Scrapy พร้อมกับเฟรมเวิร์กการทดสอบเว็บซีลีเนียมเราจะสามารถรวบรวมข้อมูลที่แสดงในเว็บเบราว์เซอร์ปกติได้

บางสิ่งที่ควรทราบ:

  • คุณต้องติดตั้งซีลีเนียมรุ่น Python เพื่อให้สิ่งนี้ทำงานได้และคุณต้องตั้งค่าซีลีเนียมอย่างถูกต้อง นอกจากนี้ยังเป็นเพียงโปรแกรมรวบรวมข้อมูลเทมเพลต คุณสามารถมีความบ้าคลั่งมากขึ้นและก้าวหน้าขึ้นไปกับสิ่งต่าง ๆ แต่ฉันแค่ต้องการแสดงความคิดพื้นฐาน เมื่อรหัสยืนอยู่คุณจะทำการร้องขอสองครั้งสำหรับ URL ที่ให้ไว้ Scrapy ทำการร้องขอเพียงครั้งเดียวและอีกหนึ่งการร้องขอโดย Selenium ฉันแน่ใจว่ามีหลายวิธีในการทำเช่นนี้เพื่อที่คุณจะได้ทำให้ซีลีเนียมทำสิ่งหนึ่งและร้องขอเพียงอย่างเดียว แต่ฉันไม่ได้สนใจที่จะทำสิ่งนั้นและด้วยการร้องขอสองครั้งคุณก็จะรวบรวมข้อมูลหน้าเว็บด้วย Scrapy

  • สิ่งนี้ค่อนข้างมีประสิทธิภาพเพราะตอนนี้คุณมี DOM ที่เรนเดอร์ทั้งหมดแล้วให้คุณทำการตระเวนและคุณยังสามารถใช้ฟีเจอร์การรวบรวมข้อมูลที่ดีทั้งหมดใน Scrapy สิ่งนี้จะทำให้การรวบรวมข้อมูลช้าลงแน่นอน แต่ขึ้นอยู่กับว่าคุณต้องการ DOM ที่แสดงผลมากเพียงใดมันอาจคุ้มค่ากับการรอ

    from scrapy.contrib.spiders import CrawlSpider, Rule
    from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
    from scrapy.selector import HtmlXPathSelector
    from scrapy.http import Request
    
    from selenium import selenium
    
    class SeleniumSpider(CrawlSpider):
        name = "SeleniumSpider"
        start_urls = ["http://www.domain.com"]
    
        rules = (
            Rule(SgmlLinkExtractor(allow=('\.html', )), callback='parse_page',follow=True),
        )
    
        def __init__(self):
            CrawlSpider.__init__(self)
            self.verificationErrors = []
            self.selenium = selenium("localhost", 4444, "*chrome", "http://www.domain.com")
            self.selenium.start()
    
        def __del__(self):
            self.selenium.stop()
            print self.verificationErrors
            CrawlSpider.__del__(self)
    
        def parse_page(self, response):
            item = Item()
    
            hxs = HtmlXPathSelector(response)
            #Do some XPath selection with Scrapy
            hxs.select('//div').extract()
    
            sel = self.selenium
            sel.open(response.url)
    
            #Wait for javscript to load in Selenium
            time.sleep(2.5)
    
            #Do some crawling of javascript created content with Selenium
            sel.get_text("//div")
            yield item
    
    # Snippet imported from snippets.scrapy.org (which no longer works)
    # author: wynbennett
    # date  : Jun 21, 2011

การอ้างอิง: http://snipplr.com/view/66998/


วิธีแก้ปัญหาเรียบร้อย! คุณมีเคล็ดลับในการเชื่อมต่อสคริปต์นี้กับ Firefox หรือไม่? (ระบบปฏิบัติการคือ Linux Mint) ฉันได้รับ "[Errno 111] การเชื่อมต่อถูกปฏิเสธ"
Andrew

1
รหัสนี้ใช้งานไม่ได้อีกต่อไปselenium=3.3.1และpython=2.7.10ข้อผิดพลาดเมื่อนำเข้าซีลีเนียมจากซีลีเนียม
benjaminz

1
ในรุ่นของซีลีเนียมว่าคำสั่งการนำเข้าของคุณจะเป็น: from selenium import webdriverหรือchromedriverหรือสิ่งที่คุณจะได้รับการใช้ เอกสาร แก้ไข: เพิ่มการอ้างอิงเอกสารและเปลี่ยนไวยากรณ์ที่น่ากลัวของฉัน!
nulltron

Selenium Remote Control ถูกแทนที่โดย Selenium WebDriver ตามเว็บไซต์ของพวกเขา
rainbowsorbet

33

อีกวิธีหนึ่งคือการใช้ตัวจัดการการดาวน์โหลดหรือตัวจัดการการดาวน์โหลดมิดเดิลแวร์ (ดูเอกสารที่ไม่ถูกต้องสำหรับข้อมูลเพิ่มเติมเกี่ยวกับมิดเดิลแวร์ของตัวดาวน์โหลด) ต่อไปนี้เป็นคลาสตัวอย่างที่ใช้ซีลีเนียมพร้อม webless phantomjs หัวขาด:

1)กำหนดคลาสภายในmiddlewares.pyสคริปต์

from selenium import webdriver
from scrapy.http import HtmlResponse

class JsDownload(object):

    @check_spider_middleware
    def process_request(self, request, spider):
        driver = webdriver.PhantomJS(executable_path='D:\phantomjs.exe')
        driver.get(request.url)
        return HtmlResponse(request.url, encoding='utf-8', body=driver.page_source.encode('utf-8'))

2)เพิ่มJsDownload()คลาสให้กับตัวแปรDOWNLOADER_MIDDLEWAREภายในsettings.py:

DOWNLOADER_MIDDLEWARES = {'MyProj.middleware.MiddleWareModule.MiddleWareClass': 500}

3)ผสานรวมภายในHTMLResponse your_spider.pyการถอดรหัสเนื้อหาการตอบสนองจะทำให้คุณได้ผลลัพธ์ที่ต้องการ

class Spider(CrawlSpider):
    # define unique name of spider
    name = "spider"

    start_urls = ["https://www.url.de"] 

    def parse(self, response):
        # initialize items
        item = CrawlerItem()

        # store data as items
        item["js_enabled"] = response.body.decode("utf-8") 

ตัวเลือกเพิ่มเติม:
ฉันต้องการความสามารถในการบอกสไปเดอร์ต่าง ๆ ที่มิดเดิลแวร์ใช้ดังนั้นฉันจึงนำเสื้อคลุมนี้ไปใช้:

def check_spider_middleware(method):
@functools.wraps(method)
def wrapper(self, request, spider):
    msg = '%%s %s middleware step' % (self.__class__.__name__,)
    if self.__class__ in spider.middleware:
        spider.log(msg % 'executing', level=log.DEBUG)
        return method(self, request, spider)
    else:
        spider.log(msg % 'skipping', level=log.DEBUG)
        return None

return wrapper

เพื่อให้ wrapper ทำงานได้สไปเดอร์ทั้งหมดจะต้องมีอย่างน้อย:

middleware = set([])

เพื่อรวมมิดเดิลแวร์:

middleware = set([MyProj.middleware.ModuleName.ClassName])

ข้อได้เปรียบ:
ข้อได้เปรียบหลักในการใช้งานด้วยวิธีนี้แทนที่จะอยู่ในสไปเดอร์คือคุณต้องลงเอยด้วยการร้องขอเพียงครั้งเดียว ในโซลูชันของ AT ตัวอย่างเช่นตัวจัดการการดาวน์โหลดประมวลผลการร้องขอและส่งการตอบกลับไปยังสไปเดอร์ สไปเดอร์สร้างคำขอใหม่ในฟังก์ชั่น parse_page - นั่นคือคำขอสองรายการสำหรับเนื้อหาเดียวกัน


ฉันสายไป
ซัก

@ rocktheartsm4l อะไรผิดปกติกับเพียงแค่ใช้ในprocess_requests, if spider.name in ['spider1', 'spider2']แทนของมัณฑนากร
แผ่น

@pad ไม่มีอะไรผิดปกติกับสิ่งนั้น ฉันเพิ่งพบว่ามันชัดเจนสำหรับคลาสแมงมุมของฉันที่จะมีชุดมิดเดิลแวร์ชื่อ วิธีนี้ฉันสามารถดูคลาสสไปเดอร์ใด ๆ และดูว่ามิดเดิลแวร์ใดที่จะถูกดำเนินการ โครงการของฉันมีการใช้มิดเดิลแวร์จำนวนมากดังนั้นนี่จึงสมเหตุสมผล
rocktheartsm4l

นี่เป็นทางออกที่น่ากลัว ไม่เพียง แต่มันไม่ได้เกี่ยวข้องกับ scrapy แต่รหัสตัวเองนั้นไม่มีประสิทธิภาพอย่างมากรวมถึงวิธีการทั่วไปในการกำจัดจุดประสงค์ทั้งหมดของเฟรมเวิร์กการคัดลอกเว็บแบบอะซิงโครนัสซึ่งเป็นเรื่องที่สนใจ
Granitosaurus

2
มันมีประสิทธิภาพมากกว่าโซลูชันอื่น ๆ ที่ฉันเคยเห็นบน SO เนื่องจากการใช้มิดเดิลแวร์ของตัวดาวน์โหลดทำให้มันมีเพียงคำขอเดียวเท่านั้นที่สร้างขึ้นสำหรับหน้านี้ .. ถ้ามันแย่มากทำไมคุณไม่คิดหาวิธีที่ดีกว่าและแชร์แทน การเรียกร้องอย่างโจ่งแจ้งด้านเดียว "ไม่เกี่ยวข้องกับเรื่องขี้โม้" คุณกำลังสูบบุหรี่หรือเปล่า? นอกเหนือจากการใช้โซลูชันที่ซับซ้อนบ้าคลั่งที่มีประสิทธิภาพและกำหนดเองแล้วนี่คือแนวทางที่ฉันเคยเห็นคนส่วนใหญ่ใช้ ความแตกต่างเพียงอย่างเดียวคือใช้ซีลีเนียมส่วนใหญ่ในสไปเดอร์ซึ่งทำให้มีการร้องขอหลายครั้ง ...
rocktheartsm4l

10

ฉันใช้มิดเดิลแวร์ของตัวดาวน์โหลดที่กำหนดเอง แต่ไม่พอใจกับมันมากเพราะฉันไม่ได้จัดการเพื่อให้แคชใช้งานได้

วิธีที่ดีกว่าคือการใช้ตัวจัดการการดาวน์โหลดแบบกำหนดเอง

มีตัวอย่างการทำงานเป็นที่นี่ ดูเหมือนว่านี้:

# encoding: utf-8
from __future__ import unicode_literals

from scrapy import signals
from scrapy.signalmanager import SignalManager
from scrapy.responsetypes import responsetypes
from scrapy.xlib.pydispatch import dispatcher
from selenium import webdriver
from six.moves import queue
from twisted.internet import defer, threads
from twisted.python.failure import Failure


class PhantomJSDownloadHandler(object):

    def __init__(self, settings):
        self.options = settings.get('PHANTOMJS_OPTIONS', {})

        max_run = settings.get('PHANTOMJS_MAXRUN', 10)
        self.sem = defer.DeferredSemaphore(max_run)
        self.queue = queue.LifoQueue(max_run)

        SignalManager(dispatcher.Any).connect(self._close, signal=signals.spider_closed)

    def download_request(self, request, spider):
        """use semaphore to guard a phantomjs pool"""
        return self.sem.run(self._wait_request, request, spider)

    def _wait_request(self, request, spider):
        try:
            driver = self.queue.get_nowait()
        except queue.Empty:
            driver = webdriver.PhantomJS(**self.options)

        driver.get(request.url)
        # ghostdriver won't response when switch window until page is loaded
        dfd = threads.deferToThread(lambda: driver.switch_to.window(driver.current_window_handle))
        dfd.addCallback(self._response, driver, spider)
        return dfd

    def _response(self, _, driver, spider):
        body = driver.execute_script("return document.documentElement.innerHTML")
        if body.startswith("<head></head>"):  # cannot access response header in Selenium
            body = driver.execute_script("return document.documentElement.textContent")
        url = driver.current_url
        respcls = responsetypes.from_args(url=url, body=body[:100].encode('utf8'))
        resp = respcls(url=url, body=body, encoding="utf-8")

        response_failed = getattr(spider, "response_failed", None)
        if response_failed and callable(response_failed) and response_failed(resp, driver):
            driver.close()
            return defer.fail(Failure())
        else:
            self.queue.put(driver)
            return defer.succeed(resp)

    def _close(self):
        while not self.queue.empty():
            driver = self.queue.get_nowait()
            driver.close()

สมมติว่ามีดโกนของคุณเรียกว่า "มีดโกน" หากคุณใส่รหัสที่กล่าวถึงไว้ในไฟล์ที่ชื่อว่าตัวจัดการโฟลเดอร์บนรูทของโฟลเดอร์ "scraper" คุณสามารถเพิ่ม settings.py เข้าไปใน:

DOWNLOAD_HANDLERS = {
    'http': 'scraper.handlers.PhantomJSDownloadHandler',
    'https': 'scraper.handlers.PhantomJSDownloadHandler',
}

และvoilà, JS จะแยกวิเคราะห์ DOM กับแคช scrapy, ลองใหม่, ฯลฯ


ฉันชอบวิธีนี้!
rocktheartsm4l

ทางออกที่ดี ซีลีเนียมเป็นไดรเวอร์ตัวเลือกเดียวหรือไม่
ผีเสื้อ

ทางออกที่ดี ขอบคุณมาก.
CrazyGeek

4

scrapy จะถูกใช้เพื่อขูดข้อมูลไดนามิกนี้เพื่อให้สามารถใช้งานได้อย่างไร?

ฉันสงสัยว่าทำไมไม่มีใครโพสต์โซลูชันโดยใช้ Scrapy เท่านั้น

ตรวจสอบการโพสต์บล็อกจากทีมงาน Scrapy ขูด INFINITE เลื่อนหน้า ตัวอย่างเรื่องที่สนใจhttp://spidyquotes.herokuapp.com/scrollเว็บไซต์ที่ใช้การเลื่อนแบบไม่สิ้นสุด

ความคิดที่จะใช้เครื่องมือสำหรับนักพัฒนาของเบราว์เซอร์ของคุณและแจ้งให้ทราบการร้องขอ AJAX ตามแล้วข้อมูลที่สร้างการร้องขอสำหรับ Scrapy

import json
import scrapy


class SpidyQuotesSpider(scrapy.Spider):
    name = 'spidyquotes'
    quotes_base_url = 'http://spidyquotes.herokuapp.com/api/quotes?page=%s'
    start_urls = [quotes_base_url % 1]
    download_delay = 1.5

    def parse(self, response):
        data = json.loads(response.body)
        for item in data.get('quotes', []):
            yield {
                'text': item.get('text'),
                'author': item.get('author', {}).get('name'),
                'tags': item.get('tags'),
            }
        if data['has_next']:
            next_page = data['page'] + 1
            yield scrapy.Request(self.quotes_base_url % next_page)

เราเผชิญกับปัญหาเดียวกันอีกครั้ง: Scrappy ไม่ได้ถูกสร้างขึ้นเพื่อจุดประสงค์นี้และนี่คือสิ่งที่เราเผชิญกับปัญหาเดียวกัน ไปยัง phantomJS หรือตามที่คนอื่นแนะนำสร้างมิดเดิลแวร์การดาวน์โหลดของคุณเอง
rak007

@ rak007 PhantomJS กับไดรเวอร์ Chrome คุณจะแนะนำแบบไหน
Chankey Pathak

2

ใช่ Scrapy สามารถคัดลอกเว็บไซต์แบบไดนามิกเว็บไซต์ที่แสดงผลผ่าน javaScript

มีสองวิธีในการคัดลอกเว็บไซต์ประเภทนี้

ครั้งแรก

คุณสามารถใช้splashเพื่อแสดงรหัส Javascript แล้วแยกวิเคราะห์ HTML ที่แสดงผล คุณสามารถค้นหาเอกสารและโครงการได้ที่นี่Scrapy splash, git

ประการที่สอง

ในขณะที่ทุกคนกำลังระบุโดยการตรวจสอบnetwork callsใช่คุณสามารถค้นหาการเรียก api ที่ดึงข้อมูลและเยาะเย้ยการโทรในแมงมุม scrapy ของคุณอาจช่วยให้คุณได้รับข้อมูลที่ต้องการ


1

ฉันจัดการคำขอ ajax โดยใช้ Selenium และโปรแกรมควบคุมเว็บ Firefox มันไม่เร็วขนาดนั้นถ้าคุณต้องการ crawler เป็น daemon แต่ดีกว่าโซลูชันแบบแมนวล ฉันเขียนบทแนะนำสั้น ๆที่นี่เพื่อการอ้างอิง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.