由于需要在公司的内网进行神经网络建模试验(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. UIPath Level 2&3

    Level 3 走了很多弯路,但是学到了很多东西,贴一个Level3的吧,其他的省略了 认认真真独立做完Level3的两个POC,相信你对UIPath的理解会更深入一步 晚安,祝各位中秋节快乐!

  2. 像调试java一样来调试Redis lua

    高并发的系统中,redis的使用是非常频繁的,而lua脚本则更是锦上添花.因为lua脚本本身执行的时候是一个事务性的操作,不会掺杂其他外部的命令,所以很多关键的系统节点都会用redis+lua来实现一 ...

  3. 微信小程序电商实战(-)商城首页

    首先在app.json中配置页面和底部tabbar { "pages":[ "pages/index/index", "pages/kind/kind ...

  4. linux常用命令 echo输出命令

    echo输出命令 'echo [选项] [输出内容]' 选项 '-e' 支持反斜线控制的字符转换 控制字符​ \a 输出警告音 \b 退格键,也就是向左删除键 \n 换行符 \r 回车键 \t 制表符 ...

  5. 为虚机Linux系统设置静态IP,ping通外网并解决相关问题

    在虚机中安装完Linux系统后,虚机是ping不通外网的,而默认的动态IP会为之后的Hadoop应用造成不少麻烦,为了减少这些不必要的麻烦,我们把系统的IP设置为静态. 步骤: 修改系统配置文件 命令 ...

  6. [Codeforces178F2]Representative Sampling

    Problem 给定n个字符串Si,任意选出k个字符串Ai,使得其中任意两个字符串lcp之和最大. Solution 建一棵trie树,枚举每一个节点对答案的贡献,树形dp,时间复杂度像是O(N^3) ...

  7. react-redux-action

    Action 是把数据从应用(view等)传到 store 的有效载荷,store.dispatch() 将 action 传到 store. //尽量减少在 action 中传递的数据//actio ...

  8. jquery自定义函数

    /** *jquery 的拓展方法 *//** * 给btn 添加去除disabled */$.fn.disabled = function() { $(this).each(function(ind ...

  9. Linux 虚拟文件系统概述

    转自:http://blog.csdn.net/u011373710/article/details/70198080 文章梗概 本文首先以“尽量不涉及源代码”的方式讨论Linux虚拟文件系统的存在的 ...

  10. nopcommerce 4.1 core 学习 增加商城配置属性

    需求:  原本是想用nop 来做国际版的商城,可以像亚马逊那样 国内外通用,  专门增加一个跨进元素属性. 学习里面的一些架构思想.  国内的行情还是 像himall  会比较实用. 这是在商城的综合 ...