提交使用Scrapy动态呈现的表单?

时间:2015-03-21 05:16:13

标签: python selenium selenium-webdriver scrapy scrapy-spider

我正在尝试使用Scrapy提交动态生成的用户登录表单,然后在与成功登录相对应的页面上解析HTML。

我想知道如何使用Scrapy或Scrapy和Selenium的组合来做到这一点。 Selenium可以在DOM上找到元素,但我想知道在获取完整的HTML后是否可以“控制回”Scrapy,以便允许它执行表单提交并保存必要的cookie ,会话数据等,以便刮取页面。

基本上,我认为Selenium是必要的唯一原因是因为我需要在Scrapy查找<form>元素之前从Javascript呈现页面。有没有替代方案呢?

谢谢!

编辑:此问题类似于this one,但遗憾的是,已接受的答案涉及请求库而非Selenium或Scrapy。虽然在某些情况下可能会出现这种情况(watch this to learn more),正如alecxe指出的那样,如果“页面的某些部分[例如表单]通过API调用加载并在帮助中插入页面,则可能需要Selenium在浏览器中执行的javascript代码“。

1 个答案:

答案 0 :(得分:4)

Scrapy 实际上并不适合使用coursera 网站,因为它非常异步。页面的一部分通过API调用加载,并在浏览器中执行javascript代码的帮助下插入页面。 Scrapy不是浏览器,无法处理它。

这提出了重点 - 为什么不使用公开的Coursera API

除了记录的内容之外,您还可以在浏览器开发人员工具中看到其他端点 - 您需要通过身份验证才能使用它们。例如,如果您已登录,则可以看到您已经采取的课程列表:

enter image description here

呼叫memberships.v1端点。

为了举例,让我们开始selenium,登录并使用get_cookies()抓取Cookie。然后,让我们生成一个Requestmemberships.v1端点,以获取已归档课程的列表,提供我们从selenium获得的Cookie:

import json

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


LOGIN = 'email'
PASSWORD = 'password'

class CourseraSpider(scrapy.Spider):
    name = "courseraSpider"
    allowed_domains = ["coursera.org"]

    def start_requests(self):
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.get('https://www.coursera.org/login')

        form = WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.XPATH, "//div[@data-js='login-body']//div[@data-js='facebook-button-divider']/following-sibling::form")))
        email = WebDriverWait(form, 10).until(EC.visibility_of_element_located((By.ID, 'user-modal-email')))
        email.send_keys(LOGIN)

        password = form.find_element_by_name('password')
        password.send_keys(PASSWORD)

        login = form.find_element_by_xpath('//button[. = "Log In"]')
        login.click()

        WebDriverWait(self.driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//h2[. = 'My Courses']")))

        self.driver.get('https://www.coursera.org/')
        cookies = self.driver.get_cookies()

        self.driver.close()

        courses_url = 'https://www.coursera.org/api/memberships.v1'
        params = {
            'fields': 'courseId,enrolledTimestamp,grade,id,lastAccessedTimestamp,role,v1SessionId,vc,vcMembershipId,courses.v1(display,partnerIds,photoUrl,specializations,startDate,v1Details),partners.v1(homeLink,name),v1Details.v1(sessionIds),v1Sessions.v1(active,dbEndDate,durationString,hasSigTrack,startDay,startMonth,startYear),specializations.v1(logo,name,partnerIds,shortName)&includes=courseId,vcMembershipId,courses.v1(partnerIds,specializations,v1Details),v1Details.v1(sessionIds),specializations.v1(partnerIds)',
            'q': 'me',
            'showHidden': 'false',
            'filter': 'archived'
        }

        params = '&'.join(key + '=' + value for key, value in params.iteritems())
        yield scrapy.Request(courses_url + '?' + params, cookies=cookies)

    def parse(self, response):
        data = json.loads(response.body)

        for course in data['linked']['courses.v1']:
            print course['name']

对我来说,它会打印出来:

Algorithms, Part I
Computing for Data Analysis
Pattern-Oriented Software Architectures for Concurrent and Networked Software
Computer Networks

这证明我们可以从Scrapy提供selenium Cookie并成功从&#34;中提取数据仅限登录用户&#34;页。


此外,请确保您不违反Terms of Use中的规则,具体为:

  

此外,作为访问网站的条件,您同意不这样做   ......(c)使用任何大容量,自动或电子方式进入   网站(包括但不限于机器人,蜘蛛,脚本或   网络抓取工具);