Python Scrapy Selenium整合:启动浏览器并登陆

广告位

某些网站要求用户必须先登录,然后才能获取网络数据,这样爬虫程序将无法随意爬取数据。 为了登录该网站,通常有两种…

某些网站要求用户必须先登录,然后才能获取网络数据,这样爬虫程序将无法随意爬取数据。

为了登录该网站,通常有两种做法:

  1. 直接用爬虫程序向网站的登录处理程序提交请求,将用户名、密码、验证码等作为请求参数,登录成功后记录登录后的 Cookie 数据。
  2. 使用真正的浏览器来模拟登录,然后记录浏览器登录之后的 Cookie 数据。

上面两种方式的目的是一样的,都是为了登录目标网站,记录登录后的 Cookie 数据。但这两种方式各有优缺点:

  • 第一种方式需要爬虫开发人员自己来处理网站登录、Cookie 管理等复杂行为。这种方式的优点是完全由自己来控制程序,因此爬虫效率高、灵活性好;缺点是编程麻烦,尤其是当目标网站有非常强的反爬虫机制时,爬虫开发人员要花费大量的时间来处理。
  • 第二种方式则完全使用真正的浏览器(比如 Firefox、Chrome 等)来模拟登录。这种方式的优点是简单、易用,而且几乎可以轻松登录所有网站(因为本来就是用浏览器登录的,正常用户怎么访问,爬虫启动的浏览器也怎么访问);缺点是需要启动浏览器,用浏览器加载页面,因此效率较低。

在使用 Scrapy 开发爬虫程序时,经常会整合 Selenium 来启动浏览器登录。

需要指出的是,Selenium 本身与爬虫并没有多大的关系,Selenium 开始主要是作为 Web 应用的自动化测试工具来使用的,广大 Java 开发人员对 Selenium(开始是用 Java 写成的)应该非常熟悉。Selenium 可以驱动浏览器对 Web 应用进行测试,就像真正的用户在使用浏览器测试 Web 应用一样。后来的爬虫程序正是借助于 Selenium 的这个功能来驱动浏览器登录 Web 应用的。

为了在 Python 程序中使用 Selenium,需要以下 3 步:

  1. 为 Python 安装 Selenium 库。运行如下命令,即可安装 Selenium:

    pip install selenium

    运行上面命令,安装成功后将会看到如下提示信息:

    Installing collected packages: selenium
    Successfully installed selenium-3.14.0

  2. 为 Selenium 下载对应的浏览器驱动。Selenium 支持 Chrome、Firefox、Edge、Safari 等各种主流的浏览器,登录 https://selenium-python.readthedocs.io/installation.html#drivers 即可看到各浏览器驱动的下载链接。
    本章我们将驱动 Firefox 来模拟登录,因此,通过其页面的链接来下载 Firefox 对应的驱动(对于 32 位操作系统,下载 32 位的驱动;对于 64 位操作系统,下载 64 位的驱动)。下载完成后将得到一个压缩包,解压该压缩包将得到一个 geckodriver.exe 文件,可以将该文件放在任意目录下,本项目将该驱动文件直接放在项目目录下。
  3. 安装目标浏览器。比如本项目需要启动 Firefox 浏览器,那么就需要在目标机器上安装 Firefox 浏览器。
    除安装 Firefox浏览器之外,还应该将 Firefox 浏览器的可执行程序(firefox.exe)所在的目录添加到 PATH 环境变量中,以便 Selenium 能找到该浏览器。

经过上面 3 步,Python 程序即可使用 Selenium 来启动 Firefox 浏览器,并驱动 Firefox 浏览目标网站。

此处使用如下简单的程序进行测试。

  from selenium import webdriver  import time    # 通过executable_path指定浏览器驱动的路径  browser = webdriver.Firefox(executable_path="WeiboSpider/geckodriver.exe")  # 等待3秒,用于等待浏览器启动完成  time.sleep(3)  # 浏览指定网页  browser.get("http://c.biancheng.net")  # 暂停5秒  time.sleep(5)

如果成功安装了 Selenium,并成功加载了 Firefox 浏览器驱动,且 Firefox 的可执行程序所在的目录位于 PATH 环境变量中,运行上面程序,Firefox 浏览器将会被启动,并自动访问 http://c.biancheng.net 站点。

在成功安装了 Selenium、驱动及目标浏览器之后,接下来我们在 Scrapy 项目中整合 Selenium,通过 Scrapy+Selenium 来登录 weibo.com。

按照惯例,首先创建一个 Scrapy 项目。在命令行窗口中执行如下命令:

scrapy startproject WeiboSpider

然后在命令行窗口中进入 WeiboSpider 所在的目录下(不要进入 WeiboSpiderWeiboSpider 目录下),执行如下命令来生成 Spider 类:

scrapy genspider weibo_post "weibo.com"

上面两个命令执行完成后,一个简单的 Scrapy 项目就创建好了。

接下来需要修改 WeiboSpideritems.py、WeiboSpiderpipelines.py、WeiboSpiderspidersweibo_post.py、WeiboSpidersettings.py 文件,将它们全部改为使用 UTF-8 字符集来保存。

本项目不再重复介绍使用 Scrapy 爬取普通文本内容的方法,而是重点介绍在 Scrapy 项目中整合 Selenium的方法,因此不需要修改 items.py 和 pipelines.py 文件。

本项目直接修改 weibo_post.py 文件,在 Spider 类中整合 Selenium 调用 Firefox 登录 weibo.com,接下来爬虫程序即可利用登录后的 Cookie 数据来访问 weibo 内容。

使用 Selenium 调用 Firefox 登录 weibo.com,首先肯定要对 weibo.com 的登录页面进行分析,不过前面两个项目己经详细介绍了这种分析过程,故此处直接给出分析结果:

  • weibo 的登录页面是:https://weibo.com/login/。
  • 在登录页面中输入用户名的文本框是://input[@id="loginname"] 节点。
  • 在登录页面中输入密码的文本框是://input[@type="password"] 节点。
  • 在登录页面中登录按钮是://a[@node-type="submitBtn"] 节点。

通过分析得到以上内容之后,接下来可以在 Spider 类中额外定义一个方法来使用 Selenimn 调用 Firefox 登录 weibo.com。该 Spider 类的代码如下:

  import scrapy  from selenium import webdriver  import time    class WeiboPostSpider(scrapy.Spider):      name = 'weibo_post'      allowed_domains = ['weibo.com']      start_urls = ['http://weibo.com/']      def __init__(self):          # 定义保存登录成功之后的cookie的变量          self.login_cookies = []      # 定义发送请求的请求头      headers = {          "Referer": "https://weibo.com/login/",          'User-Agent': "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0"      }      def get_cookies(self):          '''使用Selenium模拟浏览器登录并获取cookies'''          cookies = []          browser = webdriver.Firefox(executable_path="geckodriver.exe")          # 等待3秒,用于等待浏览器启动完成,否则可能报错          time.sleep(3)          browser.get("https://weibo.com/login/")  #①          # 获取输入用户名的文本框          elem_user = browser.find_element_by_xpath('//input[@id="loginname"]')          # 模拟输入用户名          elem_user.send_keys('xxxxxx@sina.com') #②          # 获取输入密码的文本框          elem_pwd = browser.find_element_by_xpath('//input[@type="password"]')          # 模拟输入密码          elem_pwd.send_keys('yyyyyy')  #③          # 获取提交按钮          commit = browser.find_element_by_xpath('//a[@node-type="submitBtn"]')          # 模拟单击提交按钮          commit.click()  #④          # 暂停10秒,等待浏览器登录完成          time.sleep(10)          #登录成功后获取cookie          if "微博-随时随地发现新鲜事" in browser.title:              self.login_cookies = browser.get_cookies()          else:              print("登录失败!")      # start_requests方法会在parse方法之前执行,该方法可用于处理登录逻辑。      def start_requests(self):          self.get_cookies()          print('=====================', self.login_cookies)          # 开始访问登录后的内容          return [scrapy.Request('https://weibo.com/cyuyanzhongwenwang/',              headers=self.headers,              cookies=self.login_cookies,              callback=self.parse)]        # 解析服务器相应的内容      def parse(self, response):          print('~~~~~~~parse~~~~~')          print("是否解析成功:", in response.text)

上面程序中 ① 号代码控制 Firefox 打开 weibo.com 的登录页面:https://weibo.com/login/;② 号代码控制 Firefox 在登录页面的用户名文本框中输入用户名;③ 号代码控制 Firefox 在登录页面的密码文本框中输入密码:④ 号代码模拟用户单击登录页面中的“登录”按钮。

上面 Spider 程序重写了两个方法,start_requests(self) 和 parse(self, response),其中 start_request(self) 方法会在 Scrapy 发送请求之前执行,该方法中调用 self.get_cookies() 方法来登录 weibo.com,并保存登录之后的 Cookie 数据,这样该爬虫程序即可成功访问登录之后的 https://weibo.com/cyuyanzhongwenwang/ 页面(这是我的 weibo 主页,读者在测试时应换成登录账户对应的主页)。

本项目的 parse(self, response) 方法并未 yield item,只是简单地判断了 response 中是否包含登录账号信息,因为本项目只是示范在 Scrapy 项目中如何整合 Selenium 进行登录,至于登录之后如何提取信息,前面两个项目己多次介绍,故本项目不再重复讲解。

接下来依然需要对 settings.py 文件进行修改,增加一些自定义请求头(用于模拟浏览器),设置启用指定的 Pipeline。下面是本项目修改后的 settings.py 文件:

BOT_NAME = 'WeiboSpider'

SPIDER_MODULES = ['WeiboSpider.spiders'] NEWSPIDER_MODULE = 'WeiboSpider.spiders'

ROBOTSTXT_OBEY = False

# 配置默认的请求头
DEFAULT_REQUEST_HEADERS = {
    "User-Agent" : "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0",
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
}

# 配置使用Pipeline
ITEM_PIPELINES = {
    'WeiboSpider.pipelines.WeibospiderPipeline': 300,
}

留心上面的 ROBOTSTXT_OBEY 配置,这行配置代码指定该爬虫程序不遵守该站点下的 robot.txt 规则文件(Scrapy 默认遵守 robot.txt 规则文件),强行爬取该站点的内容。

经过上面配置,接下来在 WeiboSpider 目录下执行如下命令来启动爬虫。

scrapy crawl weibo_post

运行该爬虫程序,即可看到它会自动启动 Firefox 来登录 weibo.com ,并可以在命令行窗口中看到对应解析成功的输出信息。

从该爬虫程序的运行过程来看,整合 Selenium 之后 Scrapy 的运行速度明显慢了很多。因此,Scrapy 通常只使用 Selenium 控制浏览器执行登录,不会使用 Selenium 控制浏览器执行普通下载,普通下载使用 Scrapy 自己的下载中间件即可(效率更高)。

一句话,只要技术到位,网络上没有爬取不到的数据。当然,如果有些网站的数据属于机密数据,并且这些网站也已经采取种种措施来阻止非法访问,但是你非要越过层层限制去访问这些数据,这就涉嫌触犯法律了。因此,爬虫也要适可而止。

关于作者: Python基础入门教程

为您推荐

广告位

发表评论