Python Scrapy Selenium整合:启动浏览器并登陆
为了登录该网站,通常有两种做法:
- 直接用爬虫程序向网站的登录处理程序提交请求,将用户名、密码、验证码等作为请求参数,登录成功后记录登录后的 Cookie 数据。
- 使用真正的浏览器来模拟登录,然后记录浏览器登录之后的 Cookie 数据。
上面两种方式的目的是一样的,都是为了登录目标网站,记录登录后的 Cookie 数据。但这两种方式各有优缺点:
- 第一种方式需要爬虫开发人员自己来处理网站登录、Cookie 管理等复杂行为。这种方式的优点是完全由自己来控制程序,因此爬虫效率高、灵活性好;缺点是编程麻烦,尤其是当目标网站有非常强的反爬虫机制时,爬虫开发人员要花费大量的时间来处理。
- 第二种方式则完全使用真正的浏览器(比如 Firefox、Chrome 等)来模拟登录。这种方式的优点是简单、易用,而且几乎可以轻松登录所有网站(因为本来就是用浏览器登录的,正常用户怎么访问,爬虫启动的浏览器也怎么访问);缺点是需要启动浏览器,用浏览器加载页面,因此效率较低。
在使用 Scrapy 开发爬虫程序时,经常会整合 Selenium 来启动浏览器登录。
需要指出的是,Selenium 本身与爬虫并没有多大的关系,Selenium 开始主要是作为 Web 应用的自动化测试工具来使用的,广大 Java 开发人员对 Selenium(开始是用 Java 写成的)应该非常熟悉。Selenium 可以驱动浏览器对 Web 应用进行测试,就像真正的用户在使用浏览器测试 Web 应用一样。后来的爬虫程序正是借助于 Selenium 的这个功能来驱动浏览器登录 Web 应用的。
为了在 Python 程序中使用 Selenium,需要以下 3 步:
-
为 Python 安装 Selenium 库。运行如下命令,即可安装 Selenium:
pip install selenium
运行上面命令,安装成功后将会看到如下提示信息:Installing collected packages: selenium
Successfully installed selenium-3.14.0 -
为 Selenium 下载对应的浏览器驱动。Selenium 支持 Chrome、Firefox、Edge、Safari 等各种主流的浏览器,登录 https://selenium-python.readthedocs.io/installation.html#drivers 即可看到各浏览器驱动的下载链接。
本章我们将驱动 Firefox 来模拟登录,因此,通过其页面的链接来下载 Firefox 对应的驱动(对于 32 位操作系统,下载 32 位的驱动;对于 64 位操作系统,下载 64 位的驱动)。下载完成后将得到一个压缩包,解压该压缩包将得到一个 geckodriver.exe 文件,可以将该文件放在任意目录下,本项目将该驱动文件直接放在项目目录下。 -
安装目标浏览器。比如本项目需要启动 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 所在的目录下(不要进入 WeiboSpider\WeiboSpider 目录下),执行如下命令来生成 Spider 类:scrapy genspider weibo_post "weibo.com"
上面两个命令执行完成后,一个简单的 Scrapy 项目就创建好了。接下来需要修改 WeiboSpider\items.py、WeiboSpider\pipelines.py、WeiboSpider\spiders\weibo_post.py、WeiboSpider\settings.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,
}
经过上面配置,接下来在 WeiboSpider 目录下执行如下命令来启动爬虫。
scrapy crawl weibo_post
运行该爬虫程序,即可看到它会自动启动 Firefox 来登录 weibo.com ,并可以在命令行窗口中看到对应解析成功的输出信息。从该爬虫程序的运行过程来看,整合 Selenium 之后 Scrapy 的运行速度明显慢了很多。因此,Scrapy 通常只使用 Selenium 控制浏览器执行登录,不会使用 Selenium 控制浏览器执行普通下载,普通下载使用 Scrapy 自己的下载中间件即可(效率更高)。
一句话,只要技术到位,网络上没有爬取不到的数据。当然,如果有些网站的数据属于机密数据,并且这些网站也已经采取种种措施来阻止非法访问,但是你非要越过层层限制去访问这些数据,这就涉嫌触犯法律了。因此,爬虫也要适可而止。
所有教程
- socket
- Python基础教程
- C#教程
- MySQL函数
- MySQL
- C语言入门
- C语言专题
- C语言编译器
- C语言编程实例
- GCC编译器
- 数据结构
- C语言项目案例
- C++教程
- OpenCV
- Qt教程
- Unity 3D教程
- UE4
- STL
- Redis
- Android教程
- JavaScript
- PHP
- Mybatis
- Spring Cloud
- Maven
- vi命令
- Spring Boot
- Spring MVC
- Hibernate
- Linux
- Linux命令
- Shell脚本
- Java教程
- 设计模式
- Spring
- Servlet
- Struts2
- Java Swing
- JSP教程
- CSS教程
- TensorFlow
- 区块链
- Go语言教程
- Docker
- 编程笔记
- 资源下载
- 关于我们
- 汇编语言
- 大数据
- 云计算
- VIP视频