# 挑战18 基于Selenium与PhantomJS实现爬虫 **Repository Path**: duyuntf/syltz18 ## Basic Information - **Project Name**: 挑战18 基于Selenium与PhantomJS实现爬虫 - **Description**: 基于 Selenium 和 PhantomJS 的爬虫 介绍 Selenium 是一个 Web 自动化测试工具,最初是为网站自动化测试而开发的。 Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的页面,甚至页面截屏,或者判断网站上某些动作是否发生。它支持主流的浏览器,包括 PhantomJS 这个无界面的浏览器。 将 Selenium + PhantomJS 联合使用相当于在代码里面模拟了浏览器,我们可以使用这个组合去抓取一些 JavaScript 渲染的页面,也可以用代码模拟人的一些操作,比如点击按钮,拖动,填写表单等等。 本挑战需要大家基于 Selenium + PhantomJS 爬取实验楼 “用 Python 做 2048 游戏” 课程下的所有评论, 课程地址: https://www.shiyanlou.com/courses/427 实现的爬虫脚本为 /home/shiyanlou/spider.py,执行过程如下: $ cd /home/shiyanlou $ python3 spider.py $ ls /home/shiyanlou/co - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2018-08-30 - **Last Updated**: 2022-08-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 基于 Selenium 和 PhantomJS 的爬虫 介绍 Selenium 是一个 Web 自动化测试工具,最初是为网站自动化测试而开发的。 Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的页面,甚至页面截屏,或者判断网站上某些动作是否发生。它支持主流的浏览器,包括 PhantomJS 这个无界面的浏览器。 将 Selenium + PhantomJS 联合使用相当于在代码里面模拟了浏览器,我们可以使用这个组合去抓取一些 JavaScript 渲染的页面,也可以用代码模拟人的一些操作,比如点击按钮,拖动,填写表单等等。 本挑战需要大家基于 Selenium + PhantomJS 爬取实验楼 “用 Python 做 2048 游戏” 课程下的所有评论, 课程地址: https://www.shiyanlou.com/courses/427 实现的爬虫脚本为 /home/shiyanlou/spider.py,执行过程如下: $ cd /home/shiyanlou $ python3 spider.py $ ls /home/shiyanlou/comments.json 将结果以 JSON 格式保存到 /home/shiyanlou/comments.json。 /home/shiyanlou/comments.json 文件内容如下: 图片描述 要求: 不能直接爬取 AJAX 的 API 接口 不能直接使用 Scrapy 框架,可以基于 Scrapy 的 HtmlResponse 做数据提取 要模拟浏览器点击评论的下一页获取下一页数据 当模拟点击 下一页 按钮后,如果立即去解析页面,新页面还没有返回,你解析的还是老的页面,导致结果不符合实际,这里大家要使用 Selenium 的 显示等待 去做处理 实现原理 Selenium 是一个强大的网络数据采集工具,最初是为网站自动化测试而开发的。近几年,他还被广泛用于获取精确的网站快照,因为他们可以直接运行在浏览器上。Selenium 可以让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。 Selenium 自己不带浏览器,它需要与第三方浏览器结合在一起使用。例如,可以在实验楼桌面上的 Firefox 浏览器上运行 Selenium,可以直接看到一个 FireFox 窗口被打开,进入网站,然后执行你在代码中设置的动作。虽然使用 Firefox 浏览器看起来更清楚,但在本实验中我们采用 PhantomJS 来代替真实的浏览器结合使用。 PhantomJS 是一个 无头 的浏览器,PhantomJS 会把网站加载到内存并执行页面上的 JavaScript,但是不会向用户展示网页的图形化界面,可以用来处理 cookie、JavaScript 及 header 信息,以及任何你需要浏览器协助完成的事情。 Selenium 和 PhantomJS 的使用可以参考实验楼的课程: Python3 实现淘女郎照片爬虫 但我们仍然建议在实现过程中多参考官方的文档来获得最新的接口信息: Selenium Documentation PhantomJS Documentation 流程说明 通过 Selenium PhantomJS Webdriver 模拟浏览器获得课程评论部分的页面源码,之后通过 Scrapy 的 HtmlResponse 及 xpath 解析源码,通过 xpath 提取出评论的昵称和内容。 根据 xpath 判断评论是否存在下一页,然后使用 Selenium PhantomJS Webdriver 模拟浏览器的点击行为进入到下一页,再重复步骤 1 的操作获得下一页的评论数据。 ``` 准备 安装 Selenium,注意安装的版本: $ sudo pip3 install selenium==3.0.0 下载 PhantomJS: $ wget https://npm.taobao.org/mirrors/phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2 解压 $ tar -xjvf phantomjs-2.1.1-linux-x86_64.tar.bz2 将 phantom 执行文件添加到用户 bin 目录下: $ sudo cp phantomjs-2.1.1-linux-x86_64/bin/* /usr/local/bin ``` 代码框架 在下面的代码框架基础上,根据相关的参考资料,补充完成整个爬虫脚本中的 parse、has_next_page、goto_next_page 两个函数中的 TODO 部分代码内容,在挑战环境实现过程中需要去掉下方代码中的中文注释内容: ``` # 引入 json 包用来序列化 import json # 引入 selenium 相关内容 from selenium import webdriver from scrapy.http import HtmlResponse from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 存储爬取的结果 results = [] # 使用 xpath 解析评论数据 def parse(response): for comment in response.css('div.comment-list-item'): # 使用 xpath 提取 HTML 里的评论者昵称 name 和评论内容 content # 并存入字典 result,然后将 result 添加到列表 results 中 TODO results.append(result) # 判断是否有下一页 def has_next_page(response): # 使用 xpath 提取数据来判断是否存在下一页 # 返回 True 或者 False TODO # 进入到下一页 def goto_next_page(driver): # 使用 driver.find_element_by_xpath 获得下一页的按钮 # 然后模拟按钮的 click() 操作进入到下一页 TODO # 等待页面加载完成 def wait_page_return(driver, page): WebDriverWait(driver, 10).until( EC.text_to_be_present_in_element( (By.XPATH, '//ul[@class="pagination"]/li[@class="active"]'), str(page) ) ) # 主函数 def spider(): # 创建 PhantomJS 的 webdriver driver = webdriver.PhantomJS() # 获取第一个页面 url = 'https://www.shiyanlou.com/courses/427' driver.get(url) page = 1 while True: # 加载评论的第一页 wait_page_return(driver, page) # 获取页面源码 html = driver.page_source # 构建 HtmlResponse 对象 response = HtmlResponse(url=url, body=html.encode('utf8')) # 解析 HtmlResponse 对象获取评论数据 parse(response) # 如果是最后一页则停止爬取 if not has_next_page(response): break # 进入到下一页 page += 1 goto_next_page(driver) # 将 results 使用 json 序列化后写入文件 with open('/home/shiyanlou/comments.json', 'w') as f: f.write(json.dumps(results)) if __name__ == '__main__': spider() ``` 目标 实现的爬虫脚本为 /home/shiyanlou/spider.py 结果以 JSON 格式保存到 /home/shiyanlou/comments.json,文件中包含 “用 python 做 2048 游戏” 课程下的所有评论 提示 当到达最后一页时,下一页 按钮会变成不可点击的状态,此时下一页按钮 class 里面会出现 disabled ,可以基于此判断程序停止 显示等待的条件:当前要爬取的页数出现在了处于激活状态的分页按钮文本中 知识点 Selenium PhantomJS 参考资料 Selenium Documentation PhantomJS Documentation Python 爬虫利器五之 Selenium 的用法 最新版本 Selenium 的改动 最新版本的 Selenium 已经废弃了对 PhantomJSDriver 的支持,取而代之的是 headless 的 ChromeDriver,也就是没有浏览器界面的 Chrome,相当于 PhantomJS 的功能 。由于挑战环境没有安装 Chrome,本挑战使用了老版本的 Selenium,推荐大家在自己的项目中使用 headless 的 ChromeDriver。