由于需要在公司的内网进行神经网络建模试验(https://www.cnblogs.com/NosenLiu/articles/9463886.html),为了更方便的在内网环境下快速的查阅资料,构建深度学习模型,我决定使用爬虫来对深度学习框架keras的使用手册进行爬取。

keras中文文档的地址是 http://keras-cn.readthedocs.io/en/latest/ ,是基于英文原版使用手册https://keras.io/,由国内众多学者进行翻译所得,方便大家在学习和工作中快速的进行查阅。

在编写爬虫之前,我们需要对网站的源码进行分析,以确定抓取策略。

首先,网页分为左右两个部分,并且网站的大部分有效地址基本上都是集中在页面左侧的索引中,以<li class="toctree-l1 "></li>标签进行包围。

根据网站的这个特征,我们可以不使用传统的 URL管理器+网页下载器+解析器 的传统递归爬取模式,化繁为简,一次性的获取索引中所有的待爬取url。

其次,该页面的url不同于我们平时所浏览的.html或.jsp文件,通过浏览器的查看元素操作,可以知道该url所对应的是一个事件。应该是类似于一个action指令,服务器根据这个传入参数,来动态的返回页面。

为了正确的获取动态页面的内容,我们设计使用基于selenium+phantomJS的python语言爬虫来完成全站爬取任务。

selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等[1]。

phantomJS是一个基于 WebKit(WebKit是一个开源的浏览器引擎,Chrome,Safari就是用的这个浏览器引擎) 的服务器端 JavaScript API,python可以使用selenium执行javascript,selenium可以让浏览器自动加载页面,获取需要的数据。

关于selenium与phantomJS的用法在网上有很多讲解,本文不再赘述,仅针对该全站爬取任务进行阐述。

动态页面与静态页面的分析

不同于单个网页的下载,全站爬取的难点在于如何在爬取之后保存网页之间的正确调用关系(即点击超链接能够正确的进行页面跳转)。在目标网站 keras中文文档中,服务器通过传递进来的action,使用servlet进行应答,返回对应的页面(笔者web开发的功底不牢固,只能描述大概流程,服务器运行具体细节难以描述清楚  =。=#  )。而将这些动态页面的信息以静态方式进行存储后,只有把它们放在正确的相对路径下,才能够在流量器中正常使用,因此在下载页面的时候,需要完成以下两个工作:

工作1.获取页面所在的相对路径,并且给页面命名。通过对页面的源代码进行浏览,我们可以发现,每个页面的url就是它以/latest/为根目录的相对路径。

图1 网站主页面上的序贯模型url (相对路径)

图2 序贯模型页面的真实url (绝对路径)

根据这个特征,我们可以设计相对的函数,来获取所有待爬取页面的真实url。此外,为了能够对页面进行正确的保存,需要给文件进行命名,这里将所有页面名称定位info.html。例如,序贯模型的页面在本地就存储在  ./latest/getting_started/sequential_model/info.html 文件中。

工作2.将页面存储到本地时,将其中的超链接地址改为目标静态页面的相对路径。例如,对于主页 http://keras-cn.readthedocs.io/en/latest/,它的序贯模型索引的url如下:

而对于我们所爬取下来的静态主页 ./latest/info.html 来说,它的序贯模型索引的url如下:

我们需要精确的指向该页面在本地目录中所保存的地址。

注意:我们只修改以<li class="toctree-l1 "></li>标签进行环绕的超链接<a>,其他类似href=”#keras-cn”的链接只是JavaScript的一个位置移动操作,并不会对新的页面进行加载(这一点我花了好久时间才看懂,之前一直以为需要对 #keras-cn新建一个路径,再对其页面进行静态保存……)。

做完了上述工作,就可以对网页进行爬取了,但此时,爬取出的网页大概是这个样子:

这是因为我们此时并没有下载网页的样式文件.css与.js文件,导致一片白板。继续观察网页源码,发现该网站下所有的页面,其.css文件与.js文件路径都在页面的<head>标签内进行规定,且均指向/lastest/css/文件夹与/latest/js/文件夹。因此我们只要在存储网站主页的时候,对.css与.js文档存储一次即可。

整个网站爬取的流程如下:

①使用selenium+phantomJS打开根页面,获取页面左侧索引的全部url,将其存储在url_list中。

②调用页面保存函数,对根页面进行保存。

③下载<head>标签内的 .css 与 .js 文件。

④循环遍历url_list中的页面地址,使用selenimu的webdriver进行打开,调用页面保存函数对页面内容进行保存。

注意事项:

1.获取索引URL时,由于href给出的是相对路径,需要将相对url拼接为绝对url再存入url_list。

2.存取网页时,根据<head>中的<meta charset="utf-8">,需要将页面使用utf-8编码进行保存。具体语法如下:

 with open(save_path+page_name,'wb') as f_in:
f_in.write(driver.page_source.encode('utf-8'))

3.每爬取一个页面,暂停一段时间,这既是互联网上的礼节礼貌问题,也降低了自己被反爬措施限制的风险。

time.sleep(3)  # 勿频繁访问,以防网站封禁

在我第一次爬取tensorflow手册时,没有设置访问延迟,被网站锁了一个星期不能访问,都是血泪教训~。

4.通过代码下载的.css和.js文件有可能不全,我通过右键网页→页面另存为,获取了完整的js和css文件,将其移动到对应的/latest/css/和/latest/js/路径下即可。

具体实现:

①获取绝对url函数:

 def get_abs_url(url,href):
if '../' in href:
count = 0
while('../' in href):
count += 1
href = href[3:]
for i in range(count):
if url[-1]=='/': # 去除掉url最后一个 '/'
url = url[:-1]
rare = url.split('/')[-1]
url = url.split(rare)[0]
if href[-1]=='/':
return url+href[:-1]
else:
return url+href
elif './' in href:
href = href[2:]

使用该函数,对不同类型的相对路径进行解析,获取能正确访问对应页面的绝对url。

②保存数据函数(主要用于保存css文件和js文件)

 def save_data(driver, path):   # 这个path是指/latest/路径之后的path。 页面的话要加上  路径/info.html
if path[-4:]=='.ico':
with open('./latest/'+path,'wb') as f_in:
f_in.write(driver.page_source)
elif path[-4:]=='.css' or path[-3:]=='.js':
with open('./latest/'+path,'wb') as f_in:
f_in.write(driver.page_source.encode('utf-8'))
else:
with open('./latest/'+path+'/info.html','wb') as f_in:
f_in.write(driver.page_source.encode('utf-8'))

③保存页面函数,根据路径和页面内容,来对页面进行保存。并且对页面中的url地址进行修改,以便正确的调用静态页面。

 def save_page(driver,save_path):
with open(save_path+page_name,'wb') as f_in:
f_in.write(driver.page_source.encode('utf-8'))
temp_file_lines = []
# 下面这一步把页面中的 'layers/pooling_layer/' 改为 './layers/pooling_layer/info.html' 以方便静态调用
with open(save_path+page_name,'r', encoding="utf-8") as f_in:
f_lines = f_in.readlines()
for i in range(len(f_lines)):
if 'toctree-l1' in f_lines[i] and "href=\".\"" not in f_lines[i+1]:
temp_loc = f_lines[i+1].split('"')[3]
new_loc = './'+temp_loc+page_name
f_lines[i+1] = f_lines[i+1].split(temp_loc)[0] + new_loc + f_lines[i+1].split(temp_loc)[1]
temp_file_lines.append(f_lines[i].encode('utf-8'))
with open(save_path+page_name,'wb') as f_in:
f_in.writelines(temp_file_lines)

④文件路径获取函数

 def get_save_path(url):     # 将url变为相对的文件保存路径。
if url[-1]!='/':
url = url+'/'
rare = url.split(root_url)[1]
path = root_dir+rare
return path

通过该函数获取静态页面存储路径(相对路径)。

另外还有一些逻辑直接写在了main函数里,如通过BeautifulSoup解析url地址:

 driver = webdriver.PhantomJS()
driver.get(root_url)
li_list = BeautifulSoup(driver.page_source,'html.parser').find_all('li',class_='toctree-l1')

通过<head>标签解析.css与.js文件地址:

 # TODO 在head标签中寻找 .css 及 .js
link_list = BeautifulSoup(driver.page_source,'html.parser').find('head').find_all('link')
script_list = BeautifulSoup(driver.page_source,'html.parser').find('head').find_all('script')
css_list = [] # 存储css文件
for link in link_list:
href = link['href']
if 'https://' in href:
css_list.append(href)
else:
css_list.append(get_abs_url(root_url,href))
js_list = [] # 存储 js 文件
for js in script_list:
try:
href = js['src']
except:
continue
if 'https://' in href:
js_list.append(href)
else:
js_list.append(get_abs_url(root_url,href))

具体的代码可从我的GitHub上进行下载。

https://github.com/NosenLiu/crawler_keras

其中的main.py便是程序代码,python3实现。

[1] https://blog.csdn.net/qq_29186489/article/details/78661008 selenium用法详解

基于selenium+phantomJS的动态网站全站爬取的更多相关文章

  1. 爬虫 (4)- Selenium与PhantomJS(chromedriver)与爬取案例

    Selenium文档 Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动操作,不同是Selenium 可以直接运行在浏览器 ...

  2. scrapy架构与目录介绍、scrapy解析数据、配置相关、全站爬取cnblogs数据、存储数据、爬虫中间件、加代理、加header、集成selenium

    今日内容概要 scrapy架构和目录介绍 scrapy解析数据 setting中相关配置 全站爬取cnblgos文章 存储数据 爬虫中间件和下载中间件 加代理,加header,集成selenium 内 ...

  3. 简书全站爬取 mysql异步保存

    # 简书网 # 数据保存在mysql中; 将selenium+chromedriver集成到scrapy; 整个网站数据爬取 # 抓取ajax数据 #爬虫文件 # -*- coding: utf-8 ...

  4. 爬虫---scrapy全站爬取

    全站爬取1 基于管道的持久化存储 数据解析(爬虫类) 将解析的数据封装到item类型的对象中(爬虫类) 将item提交给管道, yield item(爬虫类) 在管道类的process_item中接手 ...

  5. selenium跳过webdriver检测并爬取淘宝我已购买的宝贝数据

    简介 上一个博文已经讲述了如何使用selenium跳过webdriver检测并爬取天猫商品数据,所以在此不再详细讲,有需要思路的可以查看另外一篇博文. 源代码 # -*- coding: utf-8 ...

  6. scrapy_全站爬取

    如何查询scrapy有哪些模版? scrapy genspider –list 如何创建crawl模版? scrapy genspider -t crawl 域名 scrapy genspider - ...

  7. selenium实现淘宝的商品爬取

    一.问题 本次利用selenium自动化测试,完成对淘宝的爬取,这样可以避免一些反爬的措施,也是一种爬虫常用的手段.本次实战的难点: 1.如何利用selenium绕过淘宝的登录界面 2.获取淘宝的页面 ...

  8. Python 网络爬虫 007 (编程) 通过网站地图爬取目标站点的所有网页

    通过网站地图爬取目标站点的所有网页 使用的系统:Windows 10 64位 Python 语言版本:Python 2.7.10 V 使用的编程 Python 的集成开发环境:PyCharm 2016 ...

  9. 动态渲染页面爬取(Python 网络爬虫) ---Selenium的使用

    Selenium 的使用 Selenium 是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击.下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬.对于一些JavaS ...

随机推荐

  1. android使用smack实现简单登录功能

    android端采用xmpp协议实现即时通讯,在最开始的登录功能就遇到了不少障碍.首先在官网(https://www.igniterealtime.org/projects/openfire/)下载o ...

  2. 李航《统计学习方法》CH03

    CH03 k近邻法 前言 章节目录 k近邻算法 k近邻模型 模型 距离度量 k值选择 分类决策规则 k近邻法的实现: KDTree 构造KDTree 搜索KDTree 导读 kNN是一种基本分类与回归 ...

  3. JAVA入门[23]-SpringBoot配置Swagger2

    一.新建SpringBoot站点 1.新建module,然后引入pom依赖: <parent> <groupId>org.springframework.boot</gr ...

  4. Spring Boot Actuator [监控与管理]

    1. 如何添加 2. actuator 的原生端点(API) 2.1 应用类配置 2.1.1 http://localhost:8080/actuator/conditions 2.1.2 http: ...

  5. 刷题upupup【Java中Queue、Stack、Heap用法总结】

    [Queue] 先进先出(First-In-First-Out),LinkedList实现了Queue接口.它只允许在表的前端进行删除操作,而在表的后端进行插入操作. add()       增加一个 ...

  6. There are multiple modules with names that only differ in casing. 黄色warning

    There are multiple modules with names that only differ in casing.有多个模块同名仅大小写不同This can lead to unexp ...

  7. 彻底搞懂js原型与原型链

    原生的原型链 function fn(){},fn 为 Function的一个实例,原型链为 null -> Object -> Function -> fn: fn.__proto ...

  8. GDAL——命令使用专题——gdallocationinfo命令

    GDAL——命令使用专题——gdallocationinfo命令  前言 GDAL(Geospatial Data Abstraction Library)是一个在X/MIT许可协议下的开源栅格空间数 ...

  9. python之路-----前端之http协议

    一.概述 HTTP(hypertext transport protocol),即超文本传输协议.这个协议详细规定了浏览器和万维网服务器之间互相通信的规则(B/S架构). HTTP就是一个基于TCP的 ...

  10. Memory and Trident(CodeForces 712B)

    Description Memory is performing a walk on the two-dimensional plane, starting at the origin. He is ...