精华内容
下载资源
问答
  • python爬虫:爬取动态生成的DOM节点渲染数据结果,该方式不是直接拿到接口进行解析,而是XHR中看不到数据,检查网页又能看到,普通爬虫爬取下来的结果是看不到爬取到的这个数据所在的div的。
  • 基于PlayWright实现对js渲染的动态网页进行抓取,包含网页源码,截图,网站入口,网页互动过程等,支持优先级任务调度。 crawloop目前支持一下特性 原生浏览器环境,支持chrome,firefox,协程处理调度任务 完整DOM...
  • 用Python爬取由JavaScript生成的动态网页(以英雄联盟皮肤海报为例)
  • 此项目实现了动态网页的登录,增加,删除,修改等多个功能,包括前台和后台管理
  • 1号店动态网页

    2018-07-11 11:48:53
    这是一个动态网页,采用javascript,jquery来实现的,里面存在动画
  • CSS不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。 而且CSS 能够对网页中元素位置的排版进行像素级精确控制,支持几乎所有的字体字号样式,拥有对网页对象和模型样式编辑的能力。...
  • 这里有三个版本的生日祝福动态页面,里面有详细的指导教程,亲人、女朋友过生日最好的网页礼物。谁说程序员不懂情调
  • 登录动态页面

    2018-07-25 19:59:41
    动态网页 实业登录注册页面
  • 主要介绍了Vue拖拽组件列表实现动态页面配置功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
  • 所以,动态页面也是可以爬取滴。 文章目录Selenium安装SeleniumSelenium基本使用方法声明浏览器对象访问页面查找节点节点交互获取节点信息 Selenium Selenium是一个用于Web应用程序测试的工具。Selenium测试直接...
  • 在使用python爬虫技术采集数据信息时,经常会遇到在返回的网页信息中,无法抓取动态加载的可用数据。例如,获取某网页中,商品价格时就会出现此类现象。如下图所示。本文将实现爬取网页中类似的动态加载的数据。 1...
  • 静态网页动态网页的区别 动态网页和静态网页的区别,首先要分别了解两个概念,就是什么是静态网页,什么是动态网页,并且学会区分哪些是静态哪些是动态。...虽然静态网页页面一旦做成,内容就不会再改变了。
  •  JSP(Java Server Pages)是建立在Servlet规范之上的动态网页开发技术,其实质是一个简化的Servlet。在JSP文件中,HTML和Java代码共同存在,其中,HTML代码用于实现网页中静态内容的显示,Java代码用于实现网页中...
  • php动态网页作业 大学生网页 php+mysql

    热门讨论 2015-05-05 13:48:28
    php动态网页作业 大学生网页 php+mysql
  • 制作的一个动态博客网站,代码中给出了详细的解释,此外操作步骤也可见我的个人博客http://blog.csdn.net/mind_programmonkey,里面有详解
  • 动态网页制作优秀作品

    热门讨论 2012-10-11 09:08:54
    网页设计与制作课程大作业 动态网页制作优秀作品
  • 主要介绍了使用java将动态网页生成静态网页示例,需要的朋友可以参考下
  • 网页动态抓取

    2018-03-21 16:34:59
    动态抓取网页内容,生成word文件,包含具体demo和所需jar包
  • js大作业写的是一个关于疫情的大作业,一共有7个页面,功能有首页,我的二维码浮动、背景音乐自动播放、表格增删改查、用户登录、用户注册、图片录播、随机数产生,算是一个比较齐全的网页。内容比较简单,都是书本...
  • 关于动态网页的源文件,也是下别人的,搭建共享
  • php动态网页设计第二版本,适合初级学者学习它。这是源文件
  • 本文实例讲述了jsp实现将动态网页转换成静态页面的方法。分享给大家供大家参考。具体如下: 如果我可以将jsp动态网页转换成静态页面,那么访问的时候就不需要频繁的访问数据库了。 jsp 显示内容缓存技巧 前段时间做...
  • 基本介绍】 JavaScript是一种基于对象和事件驱动并具有相对安全性的客户端脚本语言。同时也是一种广泛用于客户端Web开发的脚本语言,常用来给HTML网页添加动态功能,比如响应用户的各种操作。的浏览效果。
  • 三个动态表白页面

    2020-05-16 12:11:44
    这里有三个动态的表白页面,情人节程序员送给女朋友最好的礼物,谁说咱们程序员不懂浪漫 这里有三个动态的表白页面,情人节程序员送给女朋友最好的礼物,谁说咱们程序员不懂浪漫
  • 动态页面jsp简介

    2020-08-08 22:45:06
    jis技术简介动态网页开发基础动态网页基础什么是动态网页JSP简介JSP页面的组成1....当用户访问动态页面时,服务器端执行脚本语言,并根据处理结果动态生成页面。 动态页面的优势: 交互性:即页面会根据用

    动态网页开发基础

    动态网页基础

    什么是动态网页

    动态网页就是指在服务器端运行的使用程序设计的交互式网页,它们会根据某种条件的变化,返回不同的网页内容。
    动态页面需要使用的是服务器端脚本语言。例如即将介绍的jsp就是使用的Java脚本语言。当用户访问动态页面时,服务器端执行脚本语言,并根据处理结果动态生成页面。

    动态页面的优势:
    交互性:即页面会根据用户的要求和选择而动态改变和显示内容。
    自动更新:即无须改变页面的代码,便会自动生成新的页面内容。
    随机性:即当不同的时间,不同的人访问同一网址时会产生不同的页面效果。

    问答: 动态页面时静态网页的替代品吗?
    答: 各有各的特点。网站采用动态还是静态主要取决于网站功能的需求和网站内容的多少。网站简单功能少,采用静态的会比较好,反之用动态比较好。 在同一个网站上,动态网页内容和静态网页内容同时存在也是常见的。

    JSP简介

    JSp容器是web容器或应用服务器的一部分,用于对JSP页面的运行提供支持,这里使用的Tomcat服务器就属于JSP容器的一种。

    JSP页面的组成

    JSP页面时通过HTML中嵌入Java脚本语言来响应页面动态请求的,除了HTML标记和java代码,JSP中还可以包含其他一些元素,如果细分,则jsp页面有静态内容,指令,表达式,小脚本,声明,标准动作,注释等元素构成。

    <%@page import="java.text.SimpleDateFormat"%>
    <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
        pageEncoding="ISO-8859-1"%>
    <html>
    <head>
    <title>输出当前日期</title>
    </head>
    
    <!-- 这是HTML注释(客户端可以看到源代码)  -->
    <%-- 这是JSP注释模式(客户端无法看到源代码) --%>
    <body>
    你好,今天是
    <% 
    	//使用预定义的格式将日期转换为字符串
    	SimpleDateFormat formater= new SimpleDateFormat("yyyy年MM月dd 日");
    	String strCurrenTime= formater.format(new Date());
    	
    %>
    <%=strCurrenTime %>
    <%! String declare="this is declaration "; %>
    <%= declare %>
    
    </body>
    </html>
    

    在上面的示例中一共展示了六种页面元素,包含静态内容,指令,小脚本,表达式,声明,注释。
    下面一一介绍。

    1.静态页面:

    静态页面时JSP页面中的静态文本,其基本是HTML文本,与Java和Jsp语法无关。

    2.JSP指令元素:

    jsp指令元素的作用是通过设置指令中的属性,在JSP运行时,控制JSP页面的某些特性。
    JSP指令一般是以"<%@“开始,”%>"结束。

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="ISO-8859-1"%>
    

    这个就是指令代码片段。

    先重点讲解JSP指令中的page指令。
    page指令是针对当前页面进行设置的一种指令,通常位于JSP页面的顶端,在一个JSP页面中可以包含多个page指令。需要注意的是page指令只针对当前JSP页面有效。
    page指定的格式如下。
    <%@ page 属性1=“属性值” 属性2=“属性值1,属性值2”…属性n=“属性值”%>
    如果没有对page指令中的某些属性进行设置,JSP容器将使用默认指令属性值。如果要对page指令中的某一个属性设置多个值,其间以逗号相互隔开。
    page指令常用属性

    属性描述
    language指定JSP页面使用的脚本语言,默认为java
    import通过该属性引用脚本语言中使用到的类文件
    contentType用于指定MIME类型和JSP页面回应所采用的字符编码方式,默认为“text/html;charset=ISO-8859-1”

    language属性的设置方法是<%@ page language=“java”%>
    import 属性 <%@ page import=“java.util.,java.text.” %>
    contentType 属性 <%@ page contentType=“text/html;charaset=UTF-8” %>

    JSP脚本语言

    在jsp页面中,将小脚本,表达式,声明统称为JSP脚本元素,用于在JSP页面中嵌入Java代码,实现页面的动态处理。
    1.什么是小脚本:
    小脚本包含任意的Java片段,形式比较灵活,通过在JSP页面中编写小脚本可以执行复杂的操作和业务处理。编写方法是将Java程序片段插入<%%>标记中。属于小脚本的代码片段如下。

    <%
    //使用预定义的格式将日期转换为字符串
    	SimpleDateFormat formater= new SimpleDateFormat("yyyy年MM月dd 日");
    	String strCurrenTime= formater.format(new Date());
    %>
    
    <% int [] value={60,70,80};
    	for(int i:value){
    	out.print(i);
    	
    %>
    <br/>
    <%
    	}
    %>
    

    2.什么是表达式
    表达式是对数据的表示,系统将其作为一个值进行计算和显示。当需要在页面中输出一个Java变量或者表达式值时,使用表达式是非常方便的。其语法是<%=Java变量或表达式%>。
    当Web容器遇到表达式时,会计算嵌入的表达式值或者变量值,然后将计算结果输出到页面中。

    <%int [] value={60,70,80};
    	for(int i:value){
    	%>
    	
    	<%=i %>
    	<% }
    %>
    

    要注意的是,在java语言中每一条语句的末尾必须使用分号结束。而在JSP中使用用来表达式输出数据时,不能在表达式结尾处添加分号。这一点要注意。
    3.JSP声明
    在编写JSP页面程序时,有时候要为Java脚本定义成员变量和方法,这时就需要使用JSP声明来实现。声明的语法如下。
    <%! Declaration;[Declaratin;]…%> 都为全局变量。

    问题:在同一个JSP文件中,如果需要在多个地方格式化日期,如何进行简化。
    答:可以定义一个方法进行解决。

    
    <%! String formatDate(Date d){
    	java.text.SimpleDateFormat formater=new java.text.SimpleDateFormat("yyyy年MM月dd 日");
    	return  formater.format(d);
    } %>
    第一次调用
    <%=formatDate(new Date())  %>
    第二次调用
    <%=formatDate(new Date())  %>
    

    JSP中的注释

    (1)HTML注释方法:<!-- -->
    (2)JSP注释方法<%-- --%>
    (3)JSP脚本中的注释的方法和在java中是一样的。

    web页面报错

    404 页面写的不对,url没写对
    2xx (成功) 表示成功
    3xx (重定向) 一般是重定向错误
    500 服务器错误,一般是在后台编写错误。

    展开全文
  • 404动态页面模板主要是使用jquery实现动画效果,很适合对404页面有要求的朋友。
  • 静态页面和动态页面的区别

    千次阅读 2020-09-09 18:03:13
    什么是动态页面?两者有什么区别?很多不了解前端技术的人可能会认为静态页面就是一个内容固定不变,没有任何效果的页面,而动态页面则是页面非常丰富,有各种交互效果和动态效果的页面。其实这个理解是错误的。通过...

    什么是静态页面?什么是动态页面?两者有什么区别?很多不了解前端技术的人可能会认为静态页面就是一个内容固定不变,没有任何效果的页面,而动态页面则是页面非常丰富,有各种交互效果和动态效果的页面。其实这个理解是错误的。通过本篇文章的阅读,详细为大家分享一下静态页面和动态页面到底是什么,两者有什么区别。
    在这里插入图片描述

    什么是静态页面和动态页面?
      通俗的来讲,静态页面是随着HTML代码的生成,页面的内容和显示效果就基本不会发生变化(除非修改页面代码),而动态页面,虽然同样页面代码不发生变化,但是其显示的内容确实可以随着时间环境或者数据操作的结果而发生变化。因此静态页面和动态页面的认识应该定位在:是否有数据库加工这个环节。例如去购买T-shirt,我们直接从商店购买的T-shirt就是静态页面,而我们根据不同人兴趣定制T-shirt就是动态页面。
      为了更好地认识理解静态页面和动态页面,我们重点了解一下两者之间的区别。

    首先静态页面和动态页面的工作原理不同。
      静态页面中,用户通过页面操作的过程就是通过浏览器使用HTTP协议向服务器发送一个请求(Request),告诉服务器我需要展示那个页面,服务器收到请求后,直接根据用户的需求直接从文件系统中取出相应的文件,返回给浏览器,浏览器解析后为用户展示下相应的页面。
      在这里插入图片描述
      
      而动态页面中,用户通过浏览器发送的请求到达服务器之后,服务器根据请求内容从数据库中调取相应的内容组合成一个虚拟的文件,然后将文件发送给浏览器,用户才得以看到定制化的内容。
    在这里插入图片描述
      通过这两个图,我们可以非常直观的看到动态页面在相应用户的请求时还需要通过数据库获取相应的数据,就相当于你定制了一件T-shirt,工厂需要根据你的定义给你制作个性化的T-shirt。

    静态页面和动态页面的交互性差异
      静态页面以展示为主,用户仅仅是通过页面获取相应的内容,而动态页面允许用户主动参与到页面之中,例如登录功能、查询功能、定制化页面内容等等。因此从交互性的角度来看,用户在动态页面中更有参与感。目前除了一些特定的 公开性展示的门户网站以外,大部分网站都是采用动态页面。

    静态页面和动态页面的更新维护方式不同
      静态页面内容是固定的,并且以一个完整的文件保存在服务器上,如果需要修改静态页面的内容,则需要找到此页面的源文件,并修改源文件的代码才可以实现内容调整。当网站内容信息非常大时,其维护成本同样会非常的大。
      而动态页面以数据库技术为基础,当需要修改内容时,可以直接通过数据库修改,而不需要调整页面的源文件。这样可以大大降低网站维护的工作量,并且大幅度提高网站运营的效率。

    静态页面和动态页面的响应速度不同
      这个差异非常好理解,简单来说就是静态页面内容是固定的,服务器的响应时间较快,而动态页面还需要根据需求从数据库中调取相应的数据“组装”成为用户需求的页面,因此其响应速度会比较慢。还是买衣服的案例,买已经做好的衣服,可以直接买了就走,而定制衣服则需要经过工厂的加工才能得到。当然在网页的访问中,虽然动态页面相对较慢,但是其差别也仅仅是以微秒甚至更小的计时单位衡量,对于人的反映时间0.1面来说,几乎可以忽略不计。

    静态页面和动态页面的访问地址
      静态页面的每个网页都有一个固定的URL,并且页面以.htm/.html/.shtml/.xml常见形式作为后缀,而且不包含“?”,这样的链接更有利于搜索引擎抓取并且收录。而动态页面的URL包含“?”,并且一般以.asp/.php/.jsp等扩展名结尾。当然我们并不能够直接通过一个网页的URL来判断这个页面是静态页面还是动态页面。这是由于搜索引擎一般不会从一个网站的数据库中方位全部网页,因此动态页面中“?”对搜索引擎检索存在一定的问题。很多企业为了让自己网站有更多的收录,就会将动态页面的URL进行伪静态化。

    展开全文
  • Python3.X 爬虫实战(动态页面爬取解析)

    万次阅读 多人点赞 2017-07-02 20:08:34
    而且可以预测出这个爬虫应该会相对稳定,因为通过我们对这个动态页面的逆向会发现我们接下来的爬虫完全不需要面对网页 DOM 解析,而完全是标准的 RESTFUL API 调用,很赞,我们通过这个逆向就可以写出爬虫程序了,...

    【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

    1 背景

    不知不觉关于 Python 3.X 爬虫系列已经介绍了如下系列:

    《正则表达式基础》
    《Python3.X 爬虫实战(先爬起来嗨)》
    《Python3.X 爬虫实战(静态下载器与解析器)》
    《Python3.X 爬虫实战(并发爬取)》
    《Python3.X 爬虫实战(缓存与持久化)》

    到此关于 Python3.x 静态页面爬虫的基础核心基本已经介绍的差不多了,剩下的就是一些自己个性化的需求了,譬如爬取数据分析等,这种我们后面还会专门来说的。然而我们在该系列的《Python3.X 爬虫实战(静态下载器与解析器)》一文时给自己留了一个锅,这篇我们的重点就是来背这个锅———动态页面爬取解析。之所以叫动态页面爬取解析其实是相对于静态下载器与解析器来说的,因为有时候我们使用静态下载器与解析器对一些要爬取的页面进行解析时竟然没有任何数据,其实大多原因都是我们要爬取的元素是 JS 动态生成的,譬如我们爬取今日头条页面,你会发现今日头条随着我们手指上滑其页面会无限制的上拉加载更多,也就是常说的瀑布流,这时候我们就会觉得该系列前面介绍的爬取方式似乎完全无能为力了,所以我们需要寻求新的爬取解析方式,也就是动态页面爬取解析,其流行的核心主流思路是动态页面逆向分析爬取和模拟浏览器行为爬取,本篇会详细探讨说明。

    【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

    这里写图片描述

    2 Python3.X 动态页面逆向分析爬取

    以这种方式进行动态页面的爬取实质就是对页面进行逆向分析,其核心就是跟踪页面的交互行为 JS 触发调度,分析出有价值、有意义的核心调用(一般都是通过 JS 发起一个 HTTP 请求),然后我们使用 Python 直接访问逆向到的链接获取价值数据。下面我们以一个实战从头到尾来演示一遍如何逆向分析爬取动态网页今日头条的数据,目标是爬取今日头条搜索出来 list(譬如搜索美女、风景)中每个头条文章点进去详情页的所有大图,然后把他们分类下载下来,首先我们看下今日头条搜索界面如下:

    这里写图片描述

    我们爬虫要干的事就是仿照上面在搜索框输入“美女”,然后点击搜索得到结果,然后对于结果页面挨个点进去详情页面,然后把详情页面里的大图都爬取下载下来。这时候如果你上来就按照我们前面系列介绍的静态分析你会发现我们点击完搜索以后上面页面的源码中这个列表只有有限的几十项,如下:

    这里写图片描述

    然而我们期望的搜索结果可不是这点啊,所以我们尝试上滑网页会发现怎么页面的链接没变,但是每次上拉到底部就会自动加载更多 item 出来,纳尼,静态爬取遇到这种情况只能懵逼啊,所以我们接下来需要做的就是来逆向分析下我们要爬取的整个过程,使用 FireBug 等来跟踪一下,我们上滑页面时会发现每次要滑到底部页面自动加载时 FireBug 会有如下反馈:

    这里写图片描述

    看到这幅图我们简单分析会发现当上拉加载更多时每次都会触发 JS 访问一个接口去请求一个 JSON 数据回来,然后再通过 JS 动态插到了上面第二幅图源码的 <div class="sections"> 标签内部,所以可以确定这是一个动态网页,我们需要做的就是看看网页对这些 JSON 数据是如何展示的。通过观察对比我们会发现上面每次滑动到底部自动加载更多的 JS 请求链接是一个 GET 请求,如下:

    http://www.toutiao.com/search_content/?offset=20&format=json&keyword=美女&autoload=true&count=20&cur_tab=1

    可以看到参数 offset 一猜就是偏移量(不信自己可以修改使用 PostMan 看下返回数据),format 为数据返回 JSON 格式,keyword 就是我们输入的关键词,autoload 没整明白,但是无伤大雅,照着传即可, count 就是每次请求返回多少个 item,cur_tab 就是搜索页面下面的分类,1 代表综合;到此我们这个动态页面的逆向第一步(页面动态数据来源)已经分析出来了,接下来我们仔细观察上面那个链接的返回值会发现 JSON 体中会有一个 data 字段的 Object 列表,这个列表其实就是我们每次上拉加载更多网页刷新数据的来源,我们会发现上拉加载更多显示出来的 item 如下:
    这里写图片描述
    这个 item 的数据就是 JSON 里 data 列表的一项,其左侧缩略图取值字段为 image_url,标题取值字段为 title,左侧来源取值字段为 source,其他类似,当我们点击这个 item 进入正文时会发现跳转正文的链接也在这个 JSON 里,用的是 article_url 字段,当我们进入文章详情去看里面的所有大图链接会惊讶的发现原来都提前预加载数据了,这些大图链接也来自刚才那个 JSON 里,对应的字段是 image_detail 里的 url 值,棒极了,我们完全逆向成功了,而且可以预测出这个爬虫应该会相对稳定,因为通过我们对这个动态页面的逆向会发现我们接下来的爬虫完全不需要面对网页 DOM 解析,而完全是标准的 RESTFUL API 调用,很赞,我们通过这个逆向就可以写出爬虫程序了,下面给出完整程序。

    [该实例对应源码 spider_opt_analysis.py 点我获取]

    # coding=utf-8
    import json
    import os
    import re
    import urllib
    from urllib import request
    '''
    Python3.X 动态页面爬取(逆向解析)实例
    爬取今日头条关键词搜索结果的所有详细页面大图片并按照关键词及文章标题分类存储图片
    '''
    
    class CrawlOptAnalysis(object):
        def __init__(self, search_word="美女"):
            self.search_word = search_word
            self.headers = {
                'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.100 Safari/537.36',
                'X-Requested-With': 'XMLHttpRequest',
                'Host': 'www.toutiao.com',
                'Referer': 'http://www.toutiao.com/search/?keyword={0}'.format(urllib.parse.quote(self.search_word)),
                'Accept': 'application/json, text/javascript',
            }
    
        def _crawl_data(self, offset):
            '''
            模拟依据传入 offset 进行分段式上拉加载更多 item 数据爬取
            '''
            url = 'http://www.toutiao.com/search_content/?offset={0}&format=json&keyword={1}&autoload=true&count=20&cur_tab=1'.format(offset, urllib.parse.quote(self.search_word))
            print(url)
            try:
                with request.urlopen(url, timeout=10) as response:
                    content = response.read()
            except Exception as e:
                content = None
                print('crawl data exception.'+str(e))
            return content
    
        def _parse_data(self, content):
            '''
            解析每次上拉加载更多爬取的 item 数据及每个 item 点进去详情页所有大图下载链接
            [
                {'article_title':XXX, 'article_image_detail':['url1', 'url2', 'url3']},
                {'article_title':XXX, 'article_image_detail':['url1', 'url2', 'url3']}
            ]
            '''
            if content is None:
                return None
            try:
                data_list = json.loads(content)['data']
                print(data_list)
                result_list = list()
                for item in data_list:
                    result_dict = {'article_title': item['title']}
                    url_list = list()
                    for url in item['image_detail']:
                        url_list.append(url['url'])
                    result_dict['article_image_detail'] = url_list
                    result_list.append(result_dict)
            except Exception as e:
                print('parse data exception.'+str(e))
            return result_list
    
        def _save_picture(self, page_title, url):
            '''
            把爬取的所有大图下载下来
            下载目录为./output/search_word/page_title/image_file
            '''
            if url is None or page_title is None:
                print('save picture params is None!')
                return
            reg_str = r"[\/\\\:\*\?\"\<\>\|]"  #For Windows File filter: '/\:*?"<>|'
            page_title = re.sub(reg_str, "", page_title)
            save_dir = './output/{0}/{1}/'.format(self.search_word, page_title)
            if os.path.exists(save_dir) is False:
                os.makedirs(save_dir)
            save_file = save_dir + url.split("/")[-1] + '.png'
            if os.path.exists(save_file):
                return
            try:
                with request.urlopen(url, timeout=30) as response, open(save_file, 'wb') as f_save:
                    f_save.write(response.read())
                print('Image is saved! search_word={0}, page_title={1}, save_file={2}'.format(self.search_word, page_title, save_file))
            except Exception as e:
                print('save picture exception.'+str(e))
    
        def go(self):
            offset = 0
            while True:
                page_list = self._parse_data(self._crawl_data(offset))
                if page_list is None or len(page_list) <= 0:
                    break
                try:
                    for page in page_list:
                        article_title = page['article_title']
                        for img in page['article_image_detail']:
                            self._save_picture(article_title, img)
                except Exception as e:
                    print('go exception.'+str(e))
                finally:
                    offset += 20
    
    
    if __name__ == '__main__':
        #模拟今日头条搜索关键词爬取正文大图
        CrawlOptAnalysis("美女").go()
        CrawlOptAnalysis("旅游").go()
        CrawlOptAnalysis("风景").go()

    可以看到下面就是我们通过对动态网页今日头条进行逆向分析后爬取的结果(体验可以获取源码直接运行):

    这里写图片描述

    到此关于动态网页逆向分析爬取的技巧就介绍完了,除过上面这个实例以外其实我们在前面已经用过一点动态网页逆向分析了,具体留作彩蛋可以自己琢磨下我们前面系列文章的 CsdnDiscussSpider 实例中 JS 提交那段逻辑。总归我们可以发现,某种意义上来看通过逆向爬取动态网页虽然比静态页面稍显麻烦,但是其稳定性似乎要比静态网页稳定,因为大多可直接逆向的动态网页数据都是采用标准 RESTFUL API 设计的,爬取解析 API 接口数据一般比匹配解析网页源码要可靠的多;但是有时候我们无法避免使用动静结合的方式,譬如上面爬取今日头条的例子其实还可以做到先动态逆向只获取文章详情页面链接,然后再使用我们前面静态页面爬取解析的技巧去访问文章详情页面获取里面大图,因为获取 item 列表是动态页面,而点击 item 进入的文章页面是静态页面。

    【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

    3 Python3.X 模拟浏览器行为爬取

    上面我们介绍了动态页面爬取解析的逆向分析爬取方式,我们会惊讶的发现对于单一化动态网站(譬如今日头条,仅仅就是资讯流和详情页面)的逆向相对来说还是比较容易的,其逆向出来的 API 参数很好理解,只有个别看起来无关紧要的参数我们无法猜出含义,但是没有影响我们的爬虫工作。然后现实总是错综复杂的,如果我们要爬取的是一些使用航母级别技术的动态网站怎么办呢,这些网站一般都非常复杂,我们如果还想使用类似 Firebug 等工具对其逆向可能时间和人力成本有点过于昂贵 ;所以对于这类网站采用上面的逆向分析手段可能不是那么适合了,所以就出现了动态页面爬取的另一种方式———模拟浏览器渲染爬取。

    3-1 Selenium 与 PhantomJS 方式

    这种方式已经烂大街了,但是这也许是一种折中方案,因为该方式最大的问题就是非常慢,因为它是加载完网页所有资源并渲染好页面后才可以操作,Selenium 本身的定位是用来进行自动化测试的。Selenium 可以按指定的命令自动操作,而 PhantomJS 是基于 Webkit 的无界面浏览器,它能在不可见的内存中完成浏览器的常见功能,所以我们可以利用 Selenium 和 PhantomJS 来实现一个强大到可以处理 JS、Cookie、Header 和任何我们真实情况需要做的事。要用好这种方式我们必须要时刻记得查阅 Selenium 文档PhantomJS 文档,关于环境配置等里面都有介绍,这里不再 BB。下面我们就来写一个实战爬虫方便我们爬取自己 QQ 空间所有相册的所有图片,然后把图片都下载下来,因为 QQ 空间我们已经不常用了,但是舍不得里面各种相册的各种照片,又不可能一张一张去手动点击下载,所以我们就有了下面基于 Selenium 和 PhantomJS 的爬虫(呜呜,看起来更像是在给 QQ 空间 WEB 写自动化测试),如下(如果跑起来有诡异 bug,建议增加相关强制等待或者隐式等待时长即可):
    [该实例对应源码 spider_selenium_phantomjs.py 点我获取]

    import os
    import time
    from urllib import request
    from PIL import Image
    from selenium import webdriver
    '''
    爬取自己 QQ 空间所有照片
    不怎么用 QQ 空间, 但是舍不得空间的照片,一张一张下载太慢,所以按照相册趴下来硬盘留念
    '''
    class SpiderSelenium(object):
        def __init__(self, qq='', pwd=None):
            self.driver = webdriver.PhantomJS()  #Run in Ubuntu, Windows need set executable_path.
            self.driver.maximize_window()
            self.qq = qq
            self.pwd = pwd
            print('webdriver start init success!')
    
        def __del__(self):
            try:
                self.driver.close()
                self.driver.quit()
                print('webdriver close and quit success!')
            except:
                pass
    
        def _need_login(self):
            '''
            通过判断页面是否存在 id 为 login_div 的元素来决定是否需要登录
            :return: 未登录返回 True,反之
            '''
            try:
                self.driver.find_element_by_id('login_div')
                return True
            except:
                return False
    
        def _login(self):
            '''
            登录 QQ 空间,先点击切换到 QQ 帐号密码登录方式,然后模拟输入 QQ 帐号密码登录,
            接着通过判断页面是否存在 id 为 QM_OwnerInfo_ModifyIcon 的元素来验证是否登录成功
            :return: 登录成功返回 True,反之
            '''
            self.driver.switch_to.frame('login_frame')
            self.driver.find_element_by_id('switcher_plogin').click()
            self.driver.find_element_by_id('u').clear()
            self.driver.find_element_by_id('u').send_keys(self.qq)
            self.driver.find_element_by_id('p').clear()
            self.driver.find_element_by_id('p').send_keys(self.pwd)
            self.driver.find_element_by_id('login_button').click()
            try:
                self.driver.find_element_by_id('QM_OwnerInfo_ModifyIcon')
                return True
            except:
                return False
    
        def _auto_scroll_to_bottom(self):
            '''
            将当前页面滑动到最底端
            '''
            js = "var q=document.body.scrollTop=10000"
            self.driver.execute_script(js)
            time.sleep(6)
    
        def _get_gallery_list(self, picture_callback):
            '''
            从相册列表点击一个相册进入以后依次点击该相册里每幅图片然后回调,依此重复各个相册
            所有注释掉的 self.driver.get_screenshot_as_file 与 self.driver.page_source 仅仅为了方便调试观察
            :param picture_callback: 回调函数,当点击一个相册的一幅大图时回调
            '''
            time.sleep(5)
            self._auto_scroll_to_bottom()
            #self.driver.get_screenshot_as_file('my_qzone_gallery_screen.png')
            self.driver.switch_to.frame('app_canvas_frame')
    
            elements = self.driver.find_elements_by_xpath("//a[@class='c-tx2 js-album-desc-a']")
            gallery_count = len(elements)
            index = 0
            while index < gallery_count:
                print('WHILE index='+str(index)+', gallery_count='+str(gallery_count))
                self._auto_scroll_to_bottom()
                elements = self.driver.find_elements_by_xpath("//a[@class='c-tx2 js-album-desc-a']")
                if index >= len(elements):
                    print('WHILE index='+str(index)+', elements='+str(len(elements)))
                    break
                print('size='+str(len(elements)))
                #self.driver.get_screenshot_as_file('pppp' + str(hash(elements[index])) + '.png')
                gallery_title = elements[index].text
                elements[index].click()
                time.sleep(5)
                self._auto_scroll_to_bottom()
                #self.driver.get_screenshot_as_file('a_gallery_details_list' + str(hash(elements[index])) + '.png')
                pic_elements = self.driver.find_elements_by_xpath("//*[@class='item-cover j-pl-photoitem-imgctn']")
                for pic in pic_elements:
                    pic.click()
                    time.sleep(5)
                    #self.driver.get_screenshot_as_file('details_' + str(hash(elements[index])) + '_' + str(hash(pic)) + '.png')
                    self.driver.switch_to.default_content()
                    pic_url = self.driver.find_element_by_id('js-img-border').find_element_by_tag_name('img').get_attribute('src')
                    print(gallery_title + ' ---> ' + pic_url)
                    if not picture_callback is None:
                        picture_callback(gallery_title, pic_url)
                    self.driver.find_element_by_class_name('photo_layer_close').click()
                    self.driver.switch_to.frame('app_canvas_frame')
                self.driver.back()
                time.sleep(10)
                index += 1
    
        def crawl_pictures(self):
            '''
            开始爬取 QQ 空间相册里图片
            '''
            self.driver.get('http://user.qzone.qq.com/{0}/photo'.format(self.qq))
            self.driver.implicitly_wait(20)
            if self._need_login():
                if self._login():
                    self._get_gallery_list(self._download_save_pic)
                    print("========== QQ " + str(self.qq) + " 的相册爬取下载结束 ===========")
                else:
                    print('login with '+str(self.qq)+' failed, please check your account and password!')
            else:
                print('already login with '+str(self.qq))
    
        def _download_save_pic(self, gallery_title, pic_url):
            '''
            下载指定 url 链接的图片到指定的目录下,图片文件后缀自动识别
            :param gallery_title: QQ 空间相册名
            :param pic_url: 该相册下一张详情图片的 url
            '''
            if gallery_title is None or pic_url is None:
                print('save picture params is None!')
                return
            save_dir = './output/{0}/'.format(gallery_title)
            if os.path.exists(save_dir) is False:
                os.makedirs(save_dir)
            save_file = save_dir + str(hash(gallery_title)) + '_' + str(hash(pic_url))
            if os.path.exists(save_file):
                return
            try:
                with request.urlopen(pic_url, timeout=30) as response, open(save_file, 'wb') as f_save:
                    f_save.write(response.read())
                new_stuffer_file = save_file + '.' + Image.open(save_file).format.lower()
                os.rename(save_file, new_stuffer_file)
    
                print('Image is saved! gallery_title={0}, save_file={1}'.format(gallery_title, new_stuffer_file))
            except Exception as e:
                print('save picture exception.'+str(e))
    
    
    if __name__ == '__main__':
        SpiderSelenium('请用你的QQ号替换', '请用你的QQ密码替换').crawl_pictures()

    替换 QQ 帐号密码后运行上面脚本我们等待后会得到如下结果:

    这里写图片描述

    可以发现,我们所有相册的图片都自动被爬取下来按照 QQ 空间相册名字分类存储在了本地磁盘,完全解放了双手,但是明显能感觉到的就是这种方式的爬虫是比较慢的,因为需要等待元素渲染,但是在有些时候这是不得不选择的一种折中方案,譬如 QQ 空间这个动态页面,想要逆向分析难度有点大,所以选择这种方案。

    3-2 其他方式

    模拟浏览器行为爬取除过上面介绍的 Selenium 结合 PhantomJS 方式外其实还有其他的框架,不过其原理归根结底基本都类似,譬如
    Splash、PyV8、Ghost、execjs 等,其 API 用法和上面 Selenium 大同小异,只是写法有差异而已,这里不再一一给出详细例子,感兴趣可以自己去搜搜相关官方文档照着爬爬,没啥特别的。

    3-3 对比总结

    通过介绍上面几种动态页面的爬取方式我们很容易会得出一个结论,能用逆向分析就尽量逆向,其稳定性和效率别的方案是没法比拟的。通常对于爬虫有句口口相传的真理,会点击使用浏览器 F12 大法就能解决百分之九十的爬虫问题,其他百分之十就需要我们动动脑子了。对于动态页面爬取更是这个道理了,能逆向就尽量逆向,逆向不了就寻找折中方案,折中方案里能使用深度控制 JS 脚本执行方案就尽量(难度略大),其次就是标准的基于浏览器自动化测试框架爬取。

    【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

    4 动态页面爬取其他事项

    前面静态页面爬取系列文章有人对于模拟登录提交有疑惑,这里要说明的是那里的例子虽然是在说静态页面,实质登录提交 FORM 表单算是动态页面的事情了,所以我们这里对于爬虫过程中的 FORM 表单问题再罗嗦几句。

    关于 WEB FORM 如果还不了解其实真的该补补基础了,对于爬虫 FORM 表单的提交其实还是使用 F12 大法分析网页,譬如我们看下 GitHub 的登录 FORM,如下:

    这里写图片描述

    想必懂点 WEB 开发的小伙伴都知道编写 WEB 页面 FORM 表单常见的套路就是除过可见的 FORM 元素外很多时候还会采用 hide 的 FORM 元素一同作为 FORM 提交,保证提交接口非交互参数的传递。所以我们可以看到 Github 登录页面的 FORM 里面除过存在可见的 input 元素以外还存在 hide 的 input 元素,input 元素的 name 属性就是提交时的 key 值,FORM 标签的 accept-charset 属性表示编码格式、action 属性表示表单数据的提交
    地址( # 表示当前 URL,其他值就是当前 URL + 值)、method 属 性表示 HTTP 的请求方式(这里为 POST),所以我们可以发现抓取的登录提交信息和我们上面分析的一致,如下:

    这里写图片描述

    所以对应的我们爬虫 POST 提交数据为:

    data = {
        'commit': 'Sign in',
        'utf8': '✓',
        'authenticity_token': 'PnKlT5OeM/FBf4PazfLsCrBsa4PHGAKLsg9DoosP8c1UBpOHVpShB9PwhglKgZwo5G+l45Ra/alPIUIRLVs9VA==',
        'login': '[account]',
        'password': '[password]'
    }
    #编码很重要
    data = urllib.urlencode(data)

    这样就可以登录了,不过还有一点要注意,既然登录就是一种状态,所以我们在发起爬虫登录时不要忘记开启 Cookie,这个很重要,原理就不解释了,这样就可以下次自动登录,关于使用 Python 直接获取浏览器 Cookie 来实现自动登录其实也不用过多强调了,获取浏览器 Cookie 的方式也有很多种,甚至可以选择使用 Python 的 browsercookie 模块来获取 Cookie。

    上面演示了自己编写代码开启 Cookie 及分析 FORM 表单提交和构造 dict 对象编码提交表单的过程,在实际小爬虫中关于 Cookie 我们可以自己封装一个类来处理,这样会方便许多,不过 Python 还提供了一个更加便捷的 Mechanize 模块来处理表单提交,非常遗憾的是这个模块不支持 Python3.X 版本,所以对于我们这个系列就没必要介绍了,感兴趣的可以自己使用低版本的 Python 玩玩。

    算是一个答疑,就此打住,打球去了!

    【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

    ^-^当然咯,看到这如果发现对您有帮助的话不妨扫描二维码赏点买羽毛球的小钱(现在球也挺贵的),既是一种鼓励也是一种分享,谢谢!
    这里写图片描述
    【工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果。私信联系我

    展开全文
  • HTML动态包含页面

    2016-08-29 17:30:29
    HTML动态包含页面
  • python3 动态网页爬虫

    千次阅读 多人点赞 2017-11-10 16:57:22
    一个好朋友要爬个app排行网页,我就以一杯星巴克卖出去啦。 网页链接:http://qianfan.analysys.cn/view/rank/app.html 我们使用Python3,主要用到re,urllib.request模块。一般来说爬虫的流程是这样:先看网页源...

    一个好朋友要爬个app排行网页,我就以一杯星巴克卖出去啦。
    网页链接:http://qianfan.analysys.cn/view/rank/app.html
    我们使用Python3,主要用到re,requests模块。

    一般来说爬虫的流程是这样:先看网页源代码,再找到要爬的字段出现的区域,用正则表达式找到这个字段,再打印或者导出结果。

    我们先看这个网页,需要爬的是排行、app和UV:
    我们要爬的是这三列数
    用python看下源代码(浏览器也可以,右键:查看网页源代码)

    # -*- coding:utf-8 -*-
    import re
    import urllib.request
    
    with urllib.request.urlopen('http://qianfan.analysys.cn/view/rank/app.html') as response:
        html = response.read().decode('utf-8')
    print(html)

    看到搜索微信并没有内容,判断为动态网页

    看到搜索微信并没有内容,判断为动态网页

    因此,得先找到这个网页填充数据的源文件。

    Chrome为例,F12找到Network,找一下传送方式为POST的数据页(表单数据)
    有四个POST,感觉那个appTOPRank比较靠谱
    有四个POST,感觉那个appTOPRank比较靠谱。

    看看Response
    我们看看返回的数据,发现里面有许多app的信息:类别、介绍等。

    很愉快的点开表头Headers找找它的url:
    Headers

    复制到浏览器里看看:

    chrome直接为我们建了格式,发现这与排行榜是一致的。但是只有20个。

    经过多次查找,发现这个是数量的要求,在data里,请求访问网站时需要加上这个datas:

    数量

    datas={'pageSize':'1000'}

    这个1000可以修改,你想抓几个就填几个。

    接下来就是python实现爬虫(可以直接使用):

    # -*- coding:utf-8 -*-
    import re
    import requests
    
    datas={'pageSize':'1000'}
    
    html=requests.post('http://qianfan.analysys.cn/qianfan/appTop/appTopRank',data = datas).content.decode('utf-8')     #用post的方式访问。网页解码成中文
    
    reg_rank=r'"rank":(.*?),"id"'    #找到排名所在的代码区域,复制前后内容,把需要爬的内容替换为(.*?)
    reg_app = r'"appName":"(.*?)","isDisplay"' #app名称
    reg_UV=r'"activeNums":(.*?),"trend"'  #活跃
    
    outcome_rank= re.findall(reg_rank, html)  #利用正则模块找到需要的内容
    outcome_app = re.findall(reg_app , html)
    outcome_UV = re.findall(reg_UV, html)
    
    for i in range(0,len(outcome_rank)): #以排行数量为准
        print (outcome_rank[i],outcome_app[i],outcome_UV[i])  #打印出结果,结果是个list,我们用for语句将里面的里面的内容一个一个输出。(这里就不追求格式了)
    
    
    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 912,310
精华内容 364,924
关键字:

动态页面