摘要: From:https://piaosanlang.gitbooks.io/spiders/content/ 爬虫入门初级篇 IDE 选择: PyCharm(推荐)、SublimeText3、VS2015、wingIDE 装python2还是python3 ? python社区需要很多年才能将现有的模块移植到支持python3. django web.py flask等还不支持p
Fromhttps://piaosanlang.gitbooks.io/spiders/content/
IDE 选择 PyCharm(推荐)、SublimeText3、VS2015、wingIDE
装python2还是python3
python社区需要很多年才能将现有的模块移植到支持python3. django web.py flask等还不支持python3。所以推荐安装python2 最新版。
Windows 平台
从 http://python.org/download/ 上安装Python 2.7。您需要修改 PATH 环境变量将Python的可执行程序及额外的脚本添加到系统路径中。将以下路径添加到 PATH 中:
C:\Python2.7\;C:\Python2.7\Scripts\; 。从 http://sourceforge.net/projects/pywin32/ 安装 pywin32。 请确认下载符合您系统的版本(win32或者amd64)
Linux Ubuntu 平台
安装Python sudo apt-get install python-dev python-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev
学习需求抓取的某个网站或者某个应用的内容提取有用的价值
实现手段模拟用户在浏览器或者应用(app)上的操作实现自动化的程序爬虫应用场景利用爬虫能做什么
大家最熟悉的应用场景抢票神器360抢票器、投票神器微信朋友圈投票
企业应用场景
2016年中国在线出境游市场研究报告
1、各种热门公司招聘中的职位数及月薪分布
2、对某个App的下载量跟踪
3、 饮食地图
还可以把男的排除掉只看女的
4、 票房预测
爬虫是什么
网络爬虫程序的优劣很大程度上反映了一个搜索引擎的好差。
不信你可以随便拿一个网站去查询一下各家搜索对它的网页收录情况爬虫强大程度跟搜索引擎好坏基本成正比。
搜索引擎工作原理
第一步抓取网页爬虫
搜索引擎是通过一种特定规律的软件跟踪网页的链接从一个链接爬到另外一个链接像蜘蛛在蜘蛛网上爬行一样所以被称为“蜘蛛”也被称为“机器人”。搜索引擎蜘蛛的爬行是被输入了一定的规则的它需要遵从一些命令或文件的内容。 Robots协议也称为爬虫协议、机器人协议等的全称是“网络爬虫排除标准”Robots Exclusion Protocol网站通过Robots协议告诉搜索引擎哪些页面可以抓取哪些页面不能抓取
https://www.taobao.com/robots.txt
http://www.qq.com/robots.txt
https://www.taobao.com/robots.txt
第二步数据存储
搜索引擎是通过蜘蛛跟踪链接爬行到网页并将爬行的数据存入原始页面数据库。其中的页面数据与用户浏览器得到的HTML是完全一样的。搜索引擎蜘蛛在抓取页面时也做一定的重复内容检测一旦遇到权重很低的网站上有大量抄袭、采集或者复制的内容很可能就不再爬行。
第三步预处理
搜索引擎将蜘蛛抓取回来的页面进行各种步骤的预处理。
⒈提取文字 ⒉中文分词 ⒊去停止词 ⒋消除噪音搜索引擎需要识别并消除这些噪声比如版权声明文字、导航条、广告等…… 5.正向索引 6.倒排索引 7.链接关系计算 8.特殊文件处理。 除了HTML文件外搜索引擎通常还能抓取和索引以文字为基础的多种文件类型如 PDF、Word、WPS、XLS、PPT、TXT 文件等。我们在搜索结果中也经常会看到这些文件类型。但搜索引擎还不能处理图片、视频、Flash 这类非文字内容也不能执行脚本和程序。
第四步排名提供检索服务
但是这些通用性搜索引擎也存在着一定的局限性如
(1)不同领域、不同背景的用户往往具有不同的检索目的和需求通用搜索引擎所返回的结果包含大量用户不关心的网页。
(2)通用搜索引擎的目标是尽可能大的网络覆盖率有限的搜索引擎服务器资源与无限的网络数据资源之间的矛盾将进一步加深。
(3)万维网数据形式的丰富和网络技术的不断发展图片、数据库、音频、视频多媒体等不同数据大量出现通用搜索引擎往往对这些信息含量密集且具有一定结构的数据无能为力不能很好地发现和获取。
(4)通用搜索引擎大多提供基于关键字的检索难以支持根据语义信息提出的查询。
为了解决上述问题定向抓取相关网页资源的聚焦爬虫应运而生。 聚焦爬虫是一个自动下载网页的程序它根据既定的抓取目标有选择的访问万维网上的网页与相关的链接获取所需要的信息。
与通用爬虫(general purpose web crawler)不同聚焦爬虫并不追求大的覆盖而将目标定为抓取与某一特定主题内容相关的网页为面向主题的用户查询准备数据资源。
聚焦爬虫工作原理以及关键技术概述
网络爬虫是一个自动提取网页的程序它为搜索引擎从万维网上下载网页是搜索引擎的重要组成。传统爬虫从一个或若干初始网页的URL开始获得初始网页上的URL在抓取网页的过程中不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。聚焦爬虫的工作流程较为复杂需要根据一定的网页分析算法过滤与主题无关的链接保留有用的链接并将其放入等待抓取的URL队列。然后它将根据一定的搜索策略从队列中选择下一步要抓取的网页URL并重复上述过程直到达到系统的某一条件时停止。另外所有被爬虫抓取的网页将会被系统存贮进行一定的分析、过滤并建立索引以便之后的查询和检索对于聚焦爬虫来说这一过程所得到的分析结果还可能对以后的抓取过程给出反馈和指导。
相对于通用网络爬虫聚焦爬虫还需要解决三个主要问题
(1) 对抓取目标的描述或定义
(2) 对网页或数据的分析与过滤
(3) 对URL的搜索策略。
抓取目标的描述和定义是决定网页分析算法与URL搜索策略如何制订的基础。而网页分析算法和候选URL排序算法是决定搜索引擎所提供的服务形式和爬虫网页抓取行为的关键所在。这两个部分的算法又是紧密相关的。
网络爬虫的发展趋势
随着AJAX/Web2.0的流行如何抓取AJAX等动态页面成了搜索引擎急需解决的问题如果搜索引擎依旧采用“爬”的机制是无法抓取到AJAX页面的有效数据的。 对于AJAX这样的技术所需要的爬虫引擎必须是基于驱动的。而如果想要实现事件驱动首先需要解决以下问题
第一JavaScript的交互分析和解释
第二DOM事件的处理和解释分发
第三动态DOM内容语义的抽取。
爬虫发展的几个阶段博士论文copy
第一个阶段可以说是早期爬虫斯坦福的几位同学完成的抓取当时的互联网基本都是完全开放的人类流量是主流
第二个阶段是分布式爬虫但是爬虫面对新的问题是数据量越来越大传统爬虫已经解决不了把数据都抓全的问题需要更多的爬虫于是调度问题就出现了
第三阶段是暗网爬虫。此时面对新的问题是数据之间的link越来越少比如淘宝点评这类数据彼此link很少那么抓全这些数据就很难还有一些数据是需要提交查询词才能获取比如机票查询那么需要寻找一些手段“发现”更多更完整的不是明面上的数据。
第四阶段智能爬虫这主要是爬虫又开始面对新的问题社交网络数据的抓取。
社交网络对爬虫带来的新的挑战包括
有一条账号护城河
我们通常称UGCUser Generated Content指用户原创内容。为web2.0即数据从单向传达到双向互动人民群众可以与网站产生交互因此产生了账号每个人都通过账号来标识身份提交数据这样一来社交网络就可以通过封账号来提高数据抓取的难度通过账号来发现非人类流量。之前没有账号只能通过cookie和ip。cookie又是易变易挥发的很难长期标识一个用户。
网络走向封闭
新浪微博在2012年以前都是基本不封的随便写一个程序怎么抓都不封但是很快越来越多的站点都开始防止竞争对手防止爬虫来抓取数据逐渐走向封闭越来越多的人难以获得数据。甚至都出现了专业的爬虫公司这在2010年以前是不可想象的。。
反爬手段封杀手法千差万别
写一个通用的框架抓取成百上千万的网站已经成为历史或者说已经是一个技术相对成熟的工作也就是已经有相对成熟的框架来”盗“成百上千的墓但是极个别的墓则需要特殊手段了目前市场上比较难以抓取的数据包括微信公共账号微博facebookins淘宝等等。具体原因各异但基本无法用一个统一框架来完成太特殊了。如果有一个通用的框架能解决我说的这几个网站的抓取这一定是一个非常震撼的产品如果有一定要告诉我那我公开出来然后就改行了。
当面对以上三个挑战的时候就需要智能爬虫。智能爬虫是让爬虫的行为尽可能模仿人类行为让反爬策略失效只有”混在老百姓队伍里面才是安全的“因此这就需要琢磨浏览器了很多人把爬虫写在了浏览器插件里面把爬虫写在了手机里面写在了路由器里面(春节抢票王)。再有一个传统的爬虫都是只有读操作的没有写操作这个很容易被判是爬虫智能的爬虫需要有一些自动化交互的行为这都是一些抵御反爬策略的方法。+
从商业价值上是一个能够抽象千百万网站抓取框架的爬虫工程师值钱还是一个能抓特定难抓网站的爬虫工程师值钱
能花钱来买被市场认可的数据都是那些特别难抓的抓取成本异常高的数据。
目前市场上主流的爬虫工程师都是能够抓成百上千网站的数据但如果想有价值还是得有能力抓特别难抓的数据才能估上好价钱。
爬虫是 模拟用户在浏览器或者某个应用上的操作把操作的过程、实现自动化的程序
当我们在浏览器中输入一个url后回车后台会发生什么比如说你输入http://www.sina.com.cn/
简单来说这段过程发生了以下四个步骤
1.查找域名对应的IP地址。
2.向IP对应的服务器发送请求。
3.服务器响应请求发回网页内容。
4.浏览器解析网页内容。
网络爬虫本质本质就是浏览器http请求。
浏览器和网络爬虫是两种不同的网络客户端都以相同的方式来获取网页
网络爬虫要做的简单来说就是实现浏览器的功能。通过指定url直接返回给用户所需要的数据 而不需要一步步人工去操纵浏览器获取。
浏览器是如何发送和接收这个数据呢 HTTP简介。
HTTP协议HyperText Transfer Protocol超文本传输协议目的是为了提供一种发布和接收HTML(HyperText Markup Language)页面的方法。
HTTP协议所在的协议层了解
HTTP是基于TCP协议之上的。在TCP/IP协议参考模型的各层对应的协议如下图,其中HTTP是应用层的协议。 默认HTTP的端口号为80HTTPS的端口号为443。
HTTP工作过程
一次HTTP操作称为一个事务其工作整个过程如下
1 ) 、地址解析
如用客户端浏览器请求这个页面http://localhost.com:8080/index.htm从中分解出协议名、主机名、端口、对象路径等部分对于我们的这个地址解析得到的结果如下 协议名http 主机名localhost.com 端口8080 对象路径/index.htm在这一步需要域名系统DNS解析域名localhost.com,得主机的IP地址。
2、封装HTTP请求数据包
把以上部分结合本机自己的信息封装成一个HTTP请求数据包
3封装成TCP包建立TCP连接TCP的三次握手
在HTTP工作开始之前客户机Web浏览器首先要通过网络与服务器建立连接该连接是通过TCP来完成的该协议与IP协议共同构建Internet即著名的TCP/IP协议族因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议根据规则只有低层协议建立之后才能才能进行更层协议的连接因此首先要建立TCP连接一般TCP连接的端口号是80。这里是8080端口
4客户机发送请求命令
建立连接后客户机发送一个请求给服务器请求方式的格式为统一资源标识符URL、协议版本号后边是MIME信息包括请求修饰符、客户机信息和可内容。
5服务器响应
服务器接到请求后给予相应的响应信息其格式为一个状态行包括信息的协议版本号、一个成功或错误的代码后边是MIME信息包括服务器信息、实体信息和可能的内容。
实体消息是服务器向浏览器发送头信息后它会发送一个空白行来表示头信息的发送到此为结束接着它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据
6服务器关闭TCP连接
一般情况下一旦Web服务器向浏览器发送了请求数据它就要关闭TCP连接然后如果浏览器或者服务器在其头信息加入了这行代码Connection:keep-alive
TCP连接在发送后将仍然保持打开状态于是浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间还节约了网络带宽。
HTTP协议栈数据流
HTTPS
HTTPS全称Hypertext Transfer Protocol over Secure Socket Layer是以安全为目标的HTTP通道简单讲是HTTP的安全版。即HTTP下加入SSL层HTTPS的安全基础是SSL。其所用的端口号是443。
SSL安全套接层是netscape公司设计的主要用于web的安全传输协议。这种协议在WEB上获得了广泛的应用。通过证书认证来确保客户端和网站服务器之间的通信数据是加密安全的。
有两种基本的加解密算法类型
1对称加密symmetrcic encryption密钥只有一个加密解密为同一个密码且加解密速度快典型的对称加密算法有DES、AESRC53DES等对称加密主要问题是共享秘钥除你的计算机客户端知道另外一台计算机服务器的私钥秘钥否则无法对通信流进行加密解密。解决这个问题的方案非对称秘钥。
2非对称加密使用两个秘钥公共秘钥和私有秘钥。私有秘钥由一方密码保存一般是服务器保存另一方任何人都可以获得公共秘钥。这种密钥成对出现且根据公钥无法推知私钥根据私钥也无法推知公钥加密解密使用不同密钥公钥加密需要私钥解密私钥加密需要公钥解密相对对称加密速度较慢典型的非对称加密算法有RSA、DSA等。
https通信的优点
客户端产生的密钥只有客户端和服务器端能得到
加密的数据只有客户端和服务器端才能得到明文+
客户端到服务端的通信是安全的。
网络爬虫是捜索引擎Baidu、Google、Yahoo抓取系统的重要组成部分。主要目的是将互联网上的网页下载到本地形成一个互联网内容的镜像备份。
网络爬虫的基本工作流程如下
1.首先选取一部分精心挑选的种子URL
2.将这些URL放入待抓取URL队列
3.从待抓取URL队列中取出待抓取在URL解析DNS并且得到主机的ip将URL对应的网页下载下来并存储到已下载网页库中。此外将这些URL放进已抓取URL队列。
4.分析已抓取URL队列中的URL分析其中的其他URL并且将URL放入待抓取URL队列从而进入下一个循环。
import requests #用来爬取网页
from bs4 import BeautifulSoup #用来解析网页
#我们的种子
seds = ["http://www.lagou.com/"]
sum = 0
#我们设定终止条件为爬取到10000个页面时就不玩了
while sum < 10000 :
if sum < len(seds):
r = requests.get(seds[sum])
sum = sum + 1
#提取结构化数据做存储操作
do_save_action(r)
soup = BeautifulSoup(r.content)
urls = soup.find_all("href",.....) //解析网页所有的链接
for url in urls:
seds.append(url)
else:
break
# -*- coding:utf-8 -*-
import os
import requests
from bs4 import BeautifulSoup
def spider():
url = "http://bj.grfy.net/"
proxies = {"http": "http://172.17.18.80:8080", "https": "https://172.17.18.80:8080"}
r = requests.get(url, proxies=proxies)
html = r.content
soup = BeautifulSoup(html, "lxml")
divs = soup.find_all("div", class_="content")
print len(divs)
print soup
if __name__ == "__main__":
spider()
os.system("pause")
Fiddler抓取HTTPS设置启动Fiddler打开菜单栏中的 Tools > Fiddler Options打开“Fiddler Options”对话框。
对Fiddler进行设置打开工具栏->Tools->Fiddler Options->HTTPS
选中Capture HTTPS CONNECTs因为我们要用Fiddler获取手机客户端发出的HTTPS请求所以中间的下拉菜单中选中from remote clients only。选中下方Ignore server certificate errors.
配置Fiddler允许远程连接Fiddler 主菜单 Tools -> Fiddler Options…-> Connections页签选中Allow remote computers to connect。重启Fidler这一步很重要必须做。
Fiddler 如何捕获Chrome的会话switchyomega安装插件
工具http://www.is.org/ https://github.com/getlantern/lantern
打开网址https://chrome.google.com/webstore/search/switchyomega?hl=zh-CN
Fiddler 如何捕获Firefox的会话
能支持HTTP代理的任意程序的数据包都能被Fiddler嗅探到Fiddler的运行机制其实就是本机上监听8888端口的HTTP代理。 Fiddler2启动的时候默认IE的代理设为了127.0.0.1:8888而其他浏览器是需要手动设置的所以将Firefox的代理改为127.0.0.1:8888就可以监听数据了。 Firefox 上通过如下步骤设置代理 点击: Tools -> Options, 在Options 对话框上点击Advanced tab - > network tab -> setting.
Fiddler如何捕获HTTPS会话
默认下Fiddler不会捕获HTTPS会话需要你设置下 打开Fiddler Tool->Fiddler Options->HTTPS tab
选中checkbox 弹出如下的对话框点击"YES"
点击"Yes" 后就设置好了。
Fiddler的基本界面
特别注意 遇到这个Click请点击Click
Fiddler强大的Script系统
Fiddler包含了一个强大的基于事件脚本的子系统并且能使用.net语言进行扩展。
官方的帮助文档: http://www.fiddler2.com/Fiddler/dev/ScriptSamples.asp
首先先安装SyntaxView插件Inspectors tab->Get SyntaxView tab->Download and Install SyntaxView Now... 如下图
安装成功后Fiddler 就会多了一个Fiddler Script tab如下图
在里面我们就可以编写脚本了 看个实例让所有cnblogs的会话都显示红色。 把这段脚本放在OnBeforeRequest(oSession: Session) 方法下并且点击"Save script"
if (oSession.HostnameIs("www.cnblogs.com")) {
oSession["ui-color"] = "red";
}
这样所有的cnblogs的会话都会显示红色。
设计HTTP(HyperText Transfer Protocol)是为了提供一种发布和接收HTML(HyperText Markup Language)页面的方法。
Http两部分组成请求、响应。
客户端请求消息客户端发送一个HTTP请求到服务器的请求消息包括以下格式请求行request line、请求头部header、空行和请求数据四个部分组成下图给出了请求报文的一般格式。
服务器响应消息HTTP响应也由四个部分组成分别是状态行、消息报头、空行和响应正文。
提出一个问题
服务器和客户端的交互仅限于请求/响应过程结束之后便断开 在下一次请求服务器会认为新的客户端;为了维护他们之间的链接让服务器知道这是前一个用户发送的请求必须在一个地方保存客户端的信息Cookie通过在客户端记录信息确定用户身份。 Session通过在服务器端记录信息确定用户身份。
请求方法
根据HTTP标准HTTP请求可以使用多种请求方法。
HTTP1.0定义了三种请求方法 GET, POST 和 HEAD方法。
HTTP1.1新增了五种请求方法OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。
序号 |
方法 |
描述 |
1 |
GET |
请求指定的页面信息并返回实体主体。 |
2 |
HEAD |
类似于get请求只不过返回的响应中没有具体的内容用于获取报头 |
3 |
POST |
向指定资源提交数据进行处理请求例如提交表单或者上传文件。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 |
4 |
PUT |
从客户端向服务器传送的数据取代指定的文档的内容。 |
5 |
DELETE |
请求服务器删除指定的页面。 |
6 |
CONNECT |
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。 |
7 |
OPTIONS |
允许客户端查看服务器的性能。 |
8 |
TRACE |
回显服务器收到的请求主要用于测试或诊断。 |
GET和POST方法区别归纳如下几点
1. GET是从服务器上获取数据POST是向服务器传送数据。
2. GET请求参数显示都显示在浏览器网址上,POST请求参数在请求体当中,消息长度没有限制而且以隐式的方式进行发送
3. 尽量避免使用Get方式提交表单因为有可能会导致安全问题。 比如说在登陆表单中用Get方式用户输入的用户名和密码将在地址栏中暴露无遗。 但是在分页程序中用Get方式就比用Post好。
URL概述
统一资源定位符URL英语 Uniform / Universal Resource Locator的缩写是用于完整地描述Internet上网页和其他资源的地址的一种标识方法。
URL格式基本格式如下 schema://host[:port#]/path/…/[?query-string][#anchor]
1. schema 协议(例如http, https, ftp)
2. host 服务器的IP地址或者域名
3. port# 服务器的端口如果是走协议默认端口缺省端口80
4. path 访问资源的路径
5. query-string 参数发送给http服务器的数据
6. anchor- 锚跳转到网页的指定锚点位置
例子:
http://www.sina.com.cn/
http://192.168.0.116:8080/index.jsp
http://item.jd.com/11052214.html#product-detail
http://www.website.com/test/test.aspx?name=sv&x=true#stuff
一个URL的请求过程
当你在浏览器输入URL http://www.website.com 的时候浏览器发送一个Request去获取 http://www. website.com的html. 服务器把Response发送回给浏览器. 浏览器分析Response中的 HTML发现其中引用了很多其他文件比如图片CSS文件JS文件。 浏览器会自动再次发送Request去获取图片CSS文件或者JS文件。 当所有的文件都下载成功后 网页就被显示出来了。
常用的请求报头
HostHost初始URL中的主机和端口,用于指定被请求资源的Internet主机和端口号它通常从HTTP URL中提取出来的
Connection表示客户端与服务连接类型
1. client 发起一个包含Connection:keep-alive的请求
2. server收到请求后如果server支持keepalive回复一个包含Connection:keep-alive的响应不关闭连接否则回复一个包含Connection:close的响应关闭连接。
3. 如果client收到包含Connection:keep-alive的响应向同一个连接发送下一个请求直到一方主动关闭连接。 Keep-alive在很多情况下能够重用连接减少资源消耗缩短响应时间HTTP
Accept表示浏览器支持的 MIME 类型
MIME的英文全称是 Multipurpose Internet Mail Extensions多用途互联网邮件扩展
eg
Acceptimage/gif表明客户端希望接受GIF图象格式的资源
Accepttext/html表明客户端希望接受html文本。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
意思浏览器支持的 MIME 类型分别是 text/html、application/xhtml+xml、application/xml 和 */*优先顺序是它们从左到右的排列顺序。
Text用于标准化地表示的文本信息文本消息可以是多种字符集和或者多种格式的
Application用于传输应用程序数据或者二进制数据设定某种扩展名的文件用一种应用程序来打开的方式类型当该扩展名文件被访问的时候浏览器会自动使用指定应用程序来打开
Mime类型 |
扩展名 |
text/html |
.htm .html *.shtml |
text/plain |
text/html是以html的形式输出比如 |
application/xhtml+xml |
.xhtml .xml |
text/css |
*.css |
application/msexcel |
.xls .xla |
application/msword |
.doc .dot |
application/octet-stream |
*.exe |
application/pdf |
|
..... |
..... |
q是权重系数范围 0 =< q <= 1q 值越大请求越倾向于获得其“;”之前的类型表示的内容若没有指定 q 值越大请求越倾向于获得其“则默认为1若被赋值为0则用于提醒服务器哪些是浏览器不接受的内容类型。
Content-TypePOST 提交application/x-www-form-urlencoded 提交的数据按照 key1=val1&key2=val2 的方式进行编码key 和 val 都进行了 URL 转码。
User-Agent 浏览器类型
Referer 请求来自哪个页面用户是从该 Referer URL页面访问当前请求的页面。
Accept-Encoding浏览器支持的压缩编码类型比如gzip,支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间
eg
Accept-Encoding:gzip;q=1.0, identity; q=0.5, *;q=0 // 按顺序支持 gzip , identity
如果有多个Encoding同时匹配, 按照q值顺序排列
如果请求消息中没有设置这个域服务器假定客户端对各种内容编码都可以接受。
Accept-Language浏览器所希望的语言种类当服务器能够提供一种以上的语言版本时要用到。
eg
Accept-Language:zh-cn
如果请求消息中没有设置这个报头域服务器假定客户端对各种语言都可以接受。
Accept-Charset浏览器可接受的字符集,用于指定客户端接受的字符集
eg
Accept-Charset:iso-8859-1,gb2312
ISO8859-1通常叫做Latin-1。Latin-1包括了书写所有西方欧洲语言不可缺少的附加字符;
gb2312是标准中文字符集;
UTF-8 是 UNICODE 的一种变长字符编码可以解决多种语言文本显示问题从而实现应用国际化和本地化。
如果在请求消息中没有设置这个域缺省是任何字符集都可以接受。
掌握常用的响应状态码
服务器上每一个HTTP 应答对象response包含一个数字"状态码"。
有时状态码指出服务器无法完成请求。默认的处理器会为你处理一部分这种应答。
例如:假如response是一个"重定向"需要客户端从别的地址获取文档urllib2将为你处理。
其他不能处理的urlopen会产生一个HTTPError。
典型的错误包含"404"(页面无法找到)"403"(请求禁止)和"401"(带验证请求)。
HTTP状态码表示HTTP协议所返回的响应的状态。
比如客户端向服务器发送请求如果成功地获得请求的资源则返回的状态码为200表示响应成功。
如果请求的资源不存在 则通常返回404错误。
HTTP响应状态码通常分为5种类型分别以15五个数字开头由3位整数组成第一个数字定义了响应的类别
分类 |
分类描述 |
1** |
信息服务器收到请求需要请求者继续执行操作 |
2** |
成功操作被成功接收并处理 |
3** |
重定向需要进一步的操作以完成请求 |
4** |
客户端错误请求包含语法错误或无法完成请求 |
5** |
服务器错误服务器在处理请求的过程中发生了错误 |
最常用的响应状态码
200 (OK): 请求成功找到了该资源并且一切正常。处理方式获得响应的内容进行处理
201 请求完成结果是创建了新资源。新创建资源的URI可在响应的实体中得到 处理方式爬虫中不会遇到
202 请求被接受但处理尚未完成 处理方式阻塞等待
204 服务器端已经实现了请求但是没有返回新的信 息。如果客户是用户代理则无须为此更新自身的文档视图。 处理方式丢弃
300 该状态码不被HTTP/1.0的应用程序直接使用 只是作为3XX类型回应的默认解释。存在多个可用的被请求资源。 处理方式若程序中能够处理则进行进一步处理如果程序中不能处理则丢弃
301 (Moved Permanently): 请求的文档在其他地方新的URL在Location头中给出浏览器应该自动地访问新的URL。处理方式重定向到分配的URL
302 (Found): 类似于301但新的URL应该被视为临时性的替代而不是永久性的。处理方式重定向到临时的URL
304 (NOT MODIFIED): 该资源在上次请求之后没有任何修改。这通常用于浏览器的缓存机制。处理方式丢弃
400 (Bad Request): 请求出现语法错误。非法请求 处理方式丢弃
401 未授权 处理方式丢弃
403 (FORBIDDEN): 客户端未能获得授权。这通常是在401之后输入了不正确的用户名或密码。禁止访问 处理方式丢弃
404 (NOT FOUND): 在指定的位置不存在所申请的资源。没有找到 。 处理方式丢弃
5XX 回应代码以“5”开头的状态码表示服务器端发现自己出现错误不能继续执行请求 处理方式丢弃
500 (Internal Server Error): 服务器遇到了意料不到的情况不能完成客户的请求
503 (Service Unavailable): 服务器由于维护或者负载过重未能应答。
例如Servlet可能在数据库连接池已满的情况下返回503。服务器返回503时可以提供一个Retry-After头
常用的响应报头(了解)
Location表示客户应当到哪里去提取文档,用于重定向接受者到一个新的位置
Server服务器名字包含了服务器用来处理请求的软件信息
eg: Server响应报头域的一个例子
ServerApache-Coyote/1.1
Set-Cookie设置和页面关联的Cookie。
例如前一个 cookie 被存入浏览器并且浏览器试图请求 http://www.ibm.com/foo/index.html 时
Set-Cookiecustomer=huangxp; path=/foo; domain=.ibm.com;
expires= Wednesday, 19-OCT-05 23:12:40 GMT;
Set-Cookie的每个属性解释如下
Customer=huangxp 一个"名称值"对把名称customer设置为值"huangxp"这个属性在Cookie中必须有。
path=/foo 服务器路径。
domain=.ibm.com 指定cookie 的域名。
expires= Wednesday, 19-OCT-05 23:12:40 GMT 指定cookie 失效的时间
urllib2是python2.7自带的模块(不需要下载),它支持多种网络协议比如 FTP、HTTP、HTTPS等。 urllib2在python3.x中被改为urllib.request
利用urllib2提供了一个接口 urlopen函数
urllib2 官方文档 https://docs.python.org/2/library/urllib2.html
urlopen(url, data, timeout,....)
1第一个参数url即为URL第一个参数URL是必须要传送的
2第二个参数data是访问URL时要传送的数据data默认为空None
3第三个timeout是设置超时时间timeout默认为 60ssocket._GLOBAL_DEFAULT_TIMEOUT
GET请求方式
以传智播客官方网站 http://www.itcast.cn
import urllib2
response = urllib2.urlopen('http://www.itcast.cn/')
data = response.read()
print data
print response.code
保存成 demo.py进入该文件的目录执行如下命令查看运行结果 python demo.py
如果我想添加 Header信息怎么办 利用 urllib2.Request类
利用urllib2.Request方法,可以用来构造一个Http请求消息
正则headers 转dict
^(.*):\s(.*)$
"\1":"\2",
# -*- coding: utf-8 -*-
import urllib2
get_headers={
'Host': 'www.itcast.cn',
'Connection': 'keep-alive',
'Pragma': 'no-cache',
'Cache-Control': 'no-cache',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
#此处是压缩算法不便于查看要做解压
#'Accept-Encoding': 'gzip, deflate, sdch',
'Accept-Language': 'zh-CN,zh;q=0.8',
'Cookie': 'pgv_pvi=7044633600; tencentSig=6792114176; IESESSION=alive; pgv_si=s3489918976; CNZZDATA4617777=cnzz_eid%3D768417915-1468987955-%26ntime%3D1470191347; _qdda=3-1.1; _qddab=3-dyl6uh.ireawgo0; _qddamta_800068868=3-0'
}
request = urllib2.Request("http://www.itcast.cn/",headers=get_headers)
#request.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36')
response = urllib2.urlopen(request)
print response.code
data = response.read()
print data
提问为什么这两种写法都对
# -*- coding: utf-8 -*-
import urllib2
import urllib
proxy_handler = urllib2.ProxyHandler({"http" : 'http://192.168.17.1:8888'})
opener = urllib2.build_opener(proxy_handler)
urllib2.install_opener(opener)
Sum = 1
output = open('lagou.json', 'w')
for page in range(1,Sum+1):
formdata = 'first=false&pn='+str(page)+'&kd='
print '运行到第 (%2d) 页面' %(page)
send_headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': 'application/json, text/javascript, */*; q=0.01',
' X-Requested-With': 'XMLHttpRequest'
}
request =urllib2.Request('http://www.lagou.com/jobs/positionAjax.json?px=new&needAddtionalResult=false',headers=send_headers)
#request.add_header('X-Requested-With','XMLHttpRequest')
#request.headers=send_headers
request.add_data(formdata)
print request.get_data()
response = urllib2.urlopen(request)
print response.code
resHtml =response.read()
#print resHtml
output.write(resHtml+'\n')
output.close()
print '-'*4 + 'end'+'-'*4
提出一个问题如果要采集的是 拉钩招聘网站 北京>>朝阳区>>望京 以这个网站为例该如何理解这个url
http://www.lagou.com/jobs/list_?px=default&city=%E5%8C%97%E4%BA%AC&district=%E6%9C%9D%E9%98%B3%E5%8C%BA&bizArea=%E6%9C%9B%E4%BA%AC#filterBox
# -*- coding: utf-8 -*-
import urllib2
import urllib
query = {
'city':'北京',
'district':'朝阳区',
'bizArea':'望京'
}
print urllib.urlencode(query)
page =3
values = {
'first':'false',
'pn':str(page),
'kd':'后端开发',
}
formdata = urllib.urlencode(values)
print formdata
小结
作业
常见的加密、解密
1) MD5/SHA (单向密散列算法(Hash函数)) MessageDigest是一个数据的数字指纹.即对一个任意长度的数据进行计算,产生一个唯一指纹号. MessageDigest的特性: A) 两个不同的数据,难以生成相同的指纹号 B) 对于指定的指纹号,难以逆向计算出原始数据 代表:MD5/SHA
2) DES、AES、TEA(对称加密算法) 单密钥算法,是信息的发送方采用密钥A进行数据加密,信息的接收方采用同一个密钥A进行数据解密. 单密钥算法是一个对称算法. 缺点:由于采用同一个密钥进行加密解密,在多用户的情况下,密钥保管的安全性是一个问题. 代表:DES
3) RSA(非对称算法) RSA 是一种非对称加解密算法。 RSA is named from the initials of the authors, Ron Rivest, Adi Shamir, and Leonard Adleman,who first published the algorithm.
RSA 与 DSA 都是非对称加密算法。其中RSA的安全性是基于极其困难的大整数的分解两个素数的乘积DSA 的安全性 是基于整数有限域离散对数难题。基本上可以认为相同密钥长度的 RSA 算法与 DSA 算法安全性相当。 公钥用于加密它是向所有人公开的私钥用于解密只有密文的接收者持有。 适用OPENSSL 适用RSA 的命令如下 生成一个密钥(私钥) [root@hunterfu ~]# openssl genrsa -out private.key 1024 注意: 需要注意的是这个文件包含了公钥和密钥两部分也就是说这个文件即可用来加密也可以用来解密,后面的1024是生成 密钥的长度. 通过密钥文件private.key 提取公钥
[root@hunterfu ~]# openssl rsa -in private.key -pubout -out pub.key
使用公钥加密信息
[root@hunterfu ~]# echo -n "123456" | openssl rsautl -encrypt -inkey pub.key -pubin >encode.result
使用私钥解密信息
[root@hunterfu ~]#cat encode.result | openssl rsautl -decrypt -inkey private.key
123456
4) DSA (Digital Signature Algorithm)(数字签名算法)(非对称加密) DSA 一般用于数字签名和认证。 DSA是Schnorr和ElGamal签名算法的变种被美国NIST作为DSS(DigitalSignature Standard)。 DSA是基于整数有限域离散对数难题的其安全性与RSA相比差不多。 在DSA数字签名和认证中发送者使用自己的私钥对文件或消息进行签名接受者收到消息后使用发送者的公钥 来验证签名的真实性。DSA只是一种算法和RSA不同之处在于它不能用作加密和解密也不能进行密钥交换 只用于签名,它比RSA要快很多. 生成一个密钥(私钥)
[root@hunterfu ~]# openssl dsaparam -out dsaparam.pem 1024
[root@hunterfu ~]# openssl gendsa -out privkey.pem dsaparam.pem
生成公钥
[root@hunterfu ~]# openssl dsa -in privkey.pem -out pubkey.pem -pubout
[root@hunterfu ~]# rm -fr dsaparam.pem
# rm -fr == rm -rf == rm -r -f没区别。
使用私钥签名
[root@hunterfu ~]# echo -n "123456" | openssl dgst -dss1 -sign privkey.pem > sign.result
使用公钥验证
[root@hunterfu ~]# echo -n "123456" | openssl dgst -dss1 -verify pubkey.pem -signature sign.result
数据格式 |
描述 |
设计目标 |
XML |
Extensible Markup Language 可扩展标记语言 |
被设计为传输和存储数据其焦点是数据的内容 |
HTML |
HyperText Markup Language超文本标记语言 |
显示数据以及如何更好显示数据 |
HTML DOM |
HTML Document Object Model(文档对象模型) |
通过 JavaScript您可以重构整个HTML文档。您可以添加、移除、改变或重排页面上的项目。要改变页面的某个东西JavaScript就需要对HTML文档中所有元素进行访问的入口。 |
XML 示例
Everyday Italian
Giada De Laurentiis
2005
30.00
Harry Potter
J K. Rowling
2005
29.99
XQuery Kick Start
James McGovern
Per Bothner
Kurt Cagle
James Linn
Vaidyanathan Nagarajan
2003
49.99
Learning XML
Erik T. Ray
2003
39.95
XML DOM 定义访问和操作XML文档的标准方法。 DOM 将 XML 文档作为一个树形结构而树叶被定义为节点。
HTML DOM 示例
HTML DOM 定义了访问和操作 HTML 文档的标准方法。 DOM 以树结构表达 HTML 文档。
一般来讲对我们而言需要抓取的是某个网站或者某个应用的内容提取有用的价值内容一般分为两部分非结构化的文本或结构化的文本。
结构化的数据JSON、XML
非结构化的数据HTML文本包含JavaScript代码
HTML文本包含JavaScript代码是最常见的数据格式理应属于结构化的文本组织但因为一般我们需要的关键信息并非直接可以得到需要进行对HTML的解析查找甚至一些字符串操作才能得到所以还是归类于非结构化的数据处理中。
把网页比作一个人那么HTML便是他的骨架JS便是他的肌肉CSS便是它的衣服。
常见解析方式如下XPath、CSS选择器、正则表达式。
一段文本
例如一篇文章或者一句话我们的初衷是提取有效信息所以如果是滞后处理可以直接存储如果是需要实时提取有用信息常见的处理方式如下
分词 根据抓取的网站类型使用不同词库进行基本的分词然后变成词频统计类似于向量的表示词为方向词频为长度。
NLP 自然语言处理进行语义分析用结果表示例如正负面等。
XPath 语言XPathXML Path Language是XML路径语言,它是一种用来定位XML文档中某部分位置的语言。
将HTML转换成XML文档之后用XPath查找HTML节点或元素
比如用“/”来作为上下层级间的分隔第一个“/”表示文档的根节点注意不是指文档最外层的tag节点而是指文档本身。
比如对于一个HTML文件来说最外层的节点应该是"/html"。
XPath开发工具开源的XPath表达式编辑工具:XMLQuire(XML格式文件可用)、chrome插件 XPath Helper
firefox插件 XPath Checker
XPath语法参考文档http://www.w3school.com.cn/xpath/index.asp
XPath语法
XPath 是一门在 XML 文档中查找信息的语言。
XPath 可用来在 XML 文档中对元素和属性进行遍历。
Harry Potter
29.99
Learning XML
39.95
选取节点 XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
表达式 |
描述 |
/ |
从根节点选取。 |
nodename |
选取此节点的所有子节点。 |
// |
从当前节点 选择 所有匹配文档中的节点 |
. |
选取当前节点。 |
.. |
选取当前节点的父节点。 |
@ |
选取属性。 |
在下面的表格中我们已列出了一些路径表达式以及表达式的结果
路径表达式 |
结果 |
/bookstore |
选取根元素 bookstore。注释假如路径起始于正斜杠( / )则此路径始终代表到某元素的绝对路径 |
bookstore |
选取 bookstore 元素的所有子节点。默认从根节点选取 |
bookstore/book |
选取属于 bookstore 的子元素的所有 book 元素。 |
//book |
选取所有 book 子元素而不管它们在文档中的位置。 |
//book/./title |
选取所有 book 子元素从当前节点查找title节点 |
//price/.. |
选取所有 book 子元素从当前节点查找父节点 |
bookstore//book |
选择属于 bookstore 元素的后代的所有 book 元素而不管它们位于 bookstore 之下的什么位置。 |
//@lang |
选取名为 lang 的所有属性。 |
谓语条件Predicates
谓语用来查找某个特定的信息或者包含某个指定的值的节点。
所谓"谓语条件"就是对路径表达式的附加条件
谓语是被嵌在方括号中都写在方括号"[]"中表示对节点进行进一步的筛选。
在下面的表格中我们列出了带有谓语的一些路径表达式以及表达式的结果
路径表达式 |
结果 |
/bookstore/book[1] |
选取属于 bookstore 子元素的第一个 book 元素。 |
/bookstore/book[last()] |
选取属于 bookstore 子元素的最后一个 book 元素。 |
/bookstore/book[last()-1] |
选取属于 bookstore 子元素的倒数第二个 book 元素。 |
/bookstore/book[position()<3] |
选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 |
//title[@lang] |
选取所有拥有名为 lang 的属性的 title 元素。 |
//title[@lang=’eng’] |
选取所有 title 元素且这些元素拥有值为 eng 的 lang 属性。 |
//book[price] |
选取所有 book 元素且被选中的book元素必须带有price子元素 |
/bookstore/book[price>35.00] |
选取 bookstore 元素的所有 book 元素且其中的 price 元素的值须大于 35.00。 |
/bookstore/book[price>35.00]/title |
选取 bookstore 元素中的 book 元素的所有 title 元素且其中的 price 元素的值须大于 35.00 |
选取未知节点XPath 通配符可用来选取未知的 XML 元素。
通配符 |
描述 |
* |
匹配任何元素节点。 |
@* |
匹配任何属性节点。 |
在下面的表格中我们列出了一些路径表达式以及这些表达式的结果
路径表达式 |
结果 |
/bookstore/* |
选取 bookstore 元素的所有子元素。 |
//* |
选取文档中的所有元素。 |
//title[@*] |
选取所有带有属性的 title 元素。 |
选取若干路径 通过在路径表达式中使用“|”运算符您可以选取若干个路径。
在下面的表格中我们列出了一些路径表达式以及这些表达式的结果
路径表达式 |
结果 |
//book/title | //book/price |
选取 book 元素的所有 title 和 price 元素。 |
//title | //price |
选取文档中的所有 title 和 price 元素。 |
/bookstore/book/title | //price |
选取属于 bookstore 元素的 book 元素的所有 title 元素以及文档中所有的 price 元素。 |
XPath 高级用法
模糊查询 contains
目前许多web框架都是动态生成界面的元素id因此在每次操作相同界面时ID都是变化的这样为自动化测试造成了一定的影响。
解决方法 使用xpath的匹配功能//input[contains(@id,'nt')]
测试使用的XML
张城斌
[email protected]
http://cbcye.cnblogs.com
Gary Zhang
[email protected]
http://www.quicklearn.cn
1.查询所有Blog节点值中带有 cn 字符串的Person节点。Xpath表达式/Root//Person[contains(Blog,'cn')]
学习笔记
1.依靠自己的属性文本定位
//td[text()='Data Import']
//div[contains(@class,'cux-rightArrowIcon-on')]
//a[text()='马上注册']
//input[@type='radio' and @value='1'] 多条件
//span[@name='bruce'][text()='bruce1'][1] 多条件
//span[@id='bruce1' or text()='bruce2'] 找出多个
//span[text()='bruce1' and text()='bruce2'] 找出多个
2.依靠父节点定位
//div[@class='x-grid-col-name x-grid-cell-inner']/div
//div[@id='dynamicGridTestInstanceformclearuxformdiv']/div
//div[@id='test']/input
3.依靠子节点定位
//div[div[@id='navigation']]
//div[div[@name='listType']]
//div[p[@name='testname']]
4.混合型
//div[div[@name='listType']]//img
//td[a//font[contains(text(),'seleleium2从零开始 视屏')]]//input[@type='checkbox']
5.进阶部分
//input[@id='123']/following-sibling::input 找下一个兄弟节点
//input[@id='123']/preceding-sibling::span 上一个兄弟节点
//input[starts-with(@id,'123')] 以什么开头
//span[not(contains(text(),'xpath')] 不包含xpath字段的span
6.索引
//div/input[2]
//div[@id='position']/span[3]
//div[@id='position']/span[position()=3]
//div[@id='position']/span[position()>3]
//div[@id='position']/span[position()<3]
//div[@id='position']/span[last()]
//div[@id='position']/span[last()-1]
7.substring 截取判断
//*[substring(@id,4,5)='Every']/@id 截取该属性 定位3,取长度5的字符
//*[substring(@id,4)='EveryCookieWrap'] 截取该属性从定位3 到最后的字符
//*[substring-before(@id,'C')='swfEvery']/@id 属性 'C'之前的字符匹配
//*[substring-after(@id,'C')='ookieWrap']/@id 属性'C之后的字符匹配
8.通配符*
//span[@*='bruce']
//*[@name='bruce']
9.轴
//div[span[text()='+++current node']]/parent::div 找父节点
//div[span[text()='+++current node']]/ancestor::div 找祖先节点
10.孙子节点
//div[span[text()='current note']]/descendant::div/span[text()='123']
//div[span[text()='current note']]//div/span[text()='123'] 两个表达的意思一样
11.following pre
https://www.baidu.com/s?wd=xpath&pn=10&oq=xpath&ie=utf-8&rsv_idx=1&rsv_pq=df0399f30003691c&rsv_t=7dccXo734hMJVeb6AVGfA3434tA9U%2FXQST0DrOW%2BM8GijQ8m5rVN2R4J3gU
//span[@class="fk fk_cur"]/../following::a 往下的所有a
//span[@class="fk fk_cur"]/../preceding::a[1] 往上的所有a
xpath提取多个标签下的text
在写爬虫的时候经常会使用xpath进行数据的提取对于如下的代码
大家好
使用xpath提取是非常方便的。假设网页的源代码在selector中
data = selector.xpath('//div[@id="test1"]/text()').extract()[0]
就可以把“大家好”提取到data变量中去。
然而如果遇到下面这段代码呢
美女你的微信是多少
如果使用
data = selector.xpath('//div[@id="test2"]/text()').extract()[0]
只能提取到“美女”
如果使用
data = selector.xpath('//div[@id="test2"]/font/text()').extract()[0]
又只能提取到“你的微信是多少”
可是我本意是想把“美女你的微信是多少”这一整个句子提取出来。
我左青龙右白虎上朱雀- 下玄武。
老牛在当中龙头在胸口。
而且内部的标签还不固定如果我有一百段这样类似的html代码又如何使用xpath表达式以最快最方便的方式提取出来
使用xpath的string(.)
以第三段代码为例
data = selector.xpath('//div[@id="test3"]')
info = data.xpath('string(.)').extract()[0]
这样就可以把“我左青龙右白虎上朱雀下玄武。老牛在当中龙头在胸口”整个句子提取出来赋值给info变量。
非结构化数据之lxml库
lxml 是一种使用 Python 编写的库,可以迅速、灵活地处理 XML 支持 XPath (XML Path Language)
lxml python 官方文档 http://lxml.de/index.html
学习目的利用上节课学习的XPath语法来快速的定位 特定元素以及节点信息目的是 提取出 HTML、XML 目标数据
如何安装
Ubuntu :
sudo apt-get install libxml2-dev libxslt1-dev python-dev
sudo apt-get install zlib1g-dev
sudo apt-get install libevent-dev
sudo pip install lxml //利用 pip 安装即可
Windows:
http://blog.csdn.net/g1apassz/article/details/46574963
http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml
初步使用
首先我们利用lxml来解析 HTML 代码先来一个小例子来感受一下它的基本用法。
使用 lxml 的 etree 库然后利用 etree.HTML 初始化然后我们将其打印出来。
from lxml import etree
text = '''
'''
#Parses an HTML document from a string
html = etree.HTML(text)
#Serialize an element to an encoded string representation of its XML tree
result = etree.tostring(html)
print result
所以输出结果是这样的
不仅补全了 li 标签还添加了 bodyhtml 标签。
XPath实例测试
1获取所有的 标签
print type(html)
result = html.xpath('//li')
print result
print len(result)
print type(result)
print type(result[0])
运行结果
[, , , , ]
5
可见每个元素都是 Element 类型;是一个个的标签元素类似现在的实例
Element类型代表的就是
first item
注意
Element类型是一种灵活的容器对象用于在内存中存储结构化数据。
每个element对象都具有以下属性
1. tagstring对象标签用于标识该元素表示哪种数据即元素类型。
2. attribdictionary对象表示附有的属性。
3. textstring对象表示element的内容。
4. tailstring对象表示element闭合之后的尾迹。
实例
text tail
1 2 3 4
result[0].tag
result[0].text
result[0].tail
result[0].attrib
2获取 标签的所有 class
html.xpath('//li/@class')
运行结果:['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
3获取 标签下属性 href 为 link1.html 的 标签
html.xpath('//li/a[@href="link1.html"]')
运行结果:[]
4获取 标签下的所有 标签
注意这么写是不对的
html.xpath('//li/span')
因为 / 是用来获取子元素的而 并不是 的子元素所以要用双斜杠
html.xpath('//li//span')
运行结果:[]
5获取 标签下的所有 class不包括
html.xpath('//li/a//@class')
运行结果:['blod']
6获取最后一个 的 的 href
html.xpath('//li[last()]/a/@href')
运行结果:['link5.html']
7获取 class 为 bold 的标签名
result = html.xpath('//*[@class="bold"]')
print result[0].tag
运行结果:span
实战项目
以腾讯招聘网站为例http://hr.tencent.com/position.php?&start=10
from lxml import etree
import urllib2
import urllib
import json
request = urllib2.Request('http://hr.tencent.com/position.php?&start=10#a')
response =urllib2.urlopen(request)
resHtml = response.read()
output =open('tencent.json','w')
html = etree.HTML(resHtml)
result = html.xpath('//tr[@class="odd"] | //tr[@class="even"]')
for site in result:
item={}
name = site.xpath('./td[1]/a')[0].text
detailLink = site.xpath('./td[1]/a')[0].attrib['href']
catalog = site.xpath('./td[2]')[0].text
recruitNumber = site.xpath('./td[3]')[0].text
workLocation = site.xpath('./td[4]')[0].text
publishTime = site.xpath('./td[5]')[0].text
print type(name)
print name,detailLink,catalog,recruitNumber,workLocation,publishTime
item['name']=name
item['detailLink']=detailLink
item['catalog']=catalog
item['recruitNumber']=recruitNumber
item['publishTime']=publishTime
line = json.dumps(item,ensure_ascii=False) + '\n'
print line
output.write(line.encode('utf-8'))
output.close()
1练习一下lxml、etree、xpath的整个的操作
2试试上节课XPath的语法以及Html自己动手实践
非结构化数据之CSS SelectorCSS 选择器
CSS(即层叠样式表Cascading Stylesheet) Selector来定位locate页面上的元素Elements。Selenium官网的Document里极力推荐使用CSS locator而不是XPath来定位元素原因是CSS locator比XPath locator速度快.
Beautiful Soup
支持从HTML或XML文件中提取数据的Python库。支持Python标准库中的HTML解析器。还支持一些第三方的解析器lxml, 使用的是 Xpath 语法推荐安装。
Beautiful Soup自动将输入文档转换为Unicode编码输出文档转换为utf-8编码。你不需要考虑编码方式除非文档没有指定一个编码方式这时Beautiful Soup就不能自动识别编码方式了。然后你仅仅需要说明一下原始编码方式就可以了
Beautiful Soup4 安装
官方文档链接: https://www.crummy.com/software/BeautifulSoup/bs4/doc/
可以利用 pip来安装pip install beautifulsoup4
安装解析器(上节课已经安装过)
Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml:
另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib: pip install html5lib
下表列出了主要的解析器
解析器
使用方法
优势
劣势
Python标准库
BeautifulSoup(markup, "html.parser")
Python的内置标准库;执行速度适中;文档容错能力强
Python 2.7.3 or 3.2.2前 的版本中文档容错能力差
lxml HTML 解析器
BeautifulSoup(markup, "lxml")
速度快;文档容错能力强 ;
需要安装C语言库
lxml XML 解析器
BeautifulSoup(markup, ["lxml-xml"]) BeautifulSoup(markup, "xml")
速度快;唯一支持XML的解析器
需要安装C语言库
html5lib
BeautifulSoup(markup, "html5lib")
最好的容错性;以浏览器的方式解析文档;生成HTML5格式的文档
速度慢;不依赖外部扩展
推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定.
html_doc = """
The Dormouse's story
The Dormouse's story
Once upon a time there were three little sisters; and their names were
Elsie,
Lacie and
Tillie;
and they lived at the bottom of a well.
...
"""
使用BeautifulSoup解析这段代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
下面我们来打印一下 soup 对象的内容
print soup
格式化输出soup 对象
print(soup.prettify())
CSS选择器
在写 CSS 时标签名不加任何修饰。类名前加点。id名前加“#”。
利用类似的方法来筛选元素用到的方法是 soup.select()返回类型是 list
通过标签名查找
print soup.select('title')
#[The Dormouse's story ]
print soup.select('a')
#[, Lacie, Tillie]
print soup.select('b')
#[The Dormouse's story]
通过类名查找
print soup.select('.sister')
#[, Lacie, Tillie]
通过 id 名查找
print soup.select('#link1')
#[]
直接子标签查找
print soup.select("head > title")
#[The Dormouse's story ]
组合查找
组合查找即标签名与类名、id名进行的组合原理是一样的例如查找 p 标签中id 等于 link1的内容
属性 和 标签 不属于 同一节点 二者需要用 空格分开
print soup.select('p #link1')
#[]
属性查找
查找时还可以加入属性元素属性需要用中括号括起来
注意属性和标签属于同一节点所以中间不能加空格否则会无法匹配到
print soup.select('a[class="sister"]')
#[, Lacie, Tillie]
print soup.select('a[href="http://example.com/elsie"]')
#[]
同样属性仍然可以与上述查找方式组合。不在同一节点的使用空格隔开在同一节点的则不用加空格
print soup.select('p a[href="http://example.com/elsie"]')
#[]
以上的 select 方法返回的结果都是列表形式可以遍历形式输出
用 get_text() 方法来获取它的内容。
print soup.select('title')[0].get_text()
for title in soup.select('title'):
print title.get_text()
Tag
Tag 是什么通俗点讲就是 HTML 中的一个个标签例如
Elsie
print type(soup.select('a')[0])
输出
bs4.element.Tag
对于 Tag它有两个重要的属性是 name 和 attrs下面我们分别来感受一下
1. name
print soup.name
print soup.select('a')[0].name
输出
[document]
'a'
soup 对象本身比较特殊它的 name 即为 [document]对于其他内部标签输出的值便为标签本身的名称。
2. attrs
print soup.select('a')[0].attrs
输出
{'href': 'http://example.com/elsie', 'class': ['sister'], 'id': 'link1'}
在这里我们把 soup.select('a')[0] 标签的所有属性打印输出了出来得到的类型是一个字典。
如果我们想要单独获取某个属性可以这样例如我们获取它的 class 叫什么
print soup.select('a')[0].attrs['class']
输出
['sister']
实战案例
我们还是以 腾讯招聘网站http://hr.tencent.com/position.php?&start=10#a
from bs4 import BeautifulSoup
import urllib2
import urllib
import json
request = urllib2.Request('http://hr.tencent.com/position.php?&start=10#a')
response =urllib2.urlopen(request)
resHtml = response.read()
output =open('tencent.json','w')
html = BeautifulSoup(resHtml,'lxml')
result = html.select('tr[class="even"]')
result2 = html.select('tr[class="odd"]')
result+=result2
print len(result)
for site in result:
item={}
name = site.select('td a')[0].get_text()
detailLink = site.select('td a')[0].attrs['href']
catalog = site.select('td')[1].get_text()
recruitNumber = site.select('td')[2].get_text()
workLocation = site.select('td')[3].get_text()
publishTime = site.select('td')[4].get_text()
item['name']=name
item['detailLink']=detailLink
item['catalog']=catalog
item['recruitNumber']=recruitNumber
item['publishTime']=publishTime
line = json.dumps(item,ensure_ascii=False)
print line
output.write(line.encode('utf-8'))
output.close()
正则表达式
掌握了XPath、CSS选择器为什么还要学习正则
正则表达式用标准正则解析一般会把HTML当做普通文本用指定格式匹配当相关文本适合小片段文本或者某一串字符(比如电话号码、邮箱账户)或者
HTML包含javascript的代码无法用CSS选择器或者XPath
在线正则表达式测试网站 官方文档
正则表达式常见概念
边界匹配
^ -- 与字符串开始的地方匹配不匹配任何字符
$ -- 与字符串结束的地方匹配不匹配任何字符
str = "cat abdcatdetf ios"
^cat : 验证该行以c开头紧接着是a然后是t
ios$ : 验证该行以t结尾倒数第二个字符为a倒数第三个字符为c
^cat$: 以c开头接着是a->t然后是行结束只有cat三个字母的数据行
^$ : 开头之后马上结束空白行不包括任何字符
^ : 行的开头可以匹配任何行因为每个行都有行开头
\b -- 匹配一个单词边界也就是单词和空格之间的位置不匹配任何字符
"er\b"可以匹配"never"中的"er"但不能匹配"verb"中的"er"。
\B -- \b取非即匹配一个非单词边界
"er\B"能匹配"verb"中的"er"但不能匹配"never"中的"er"。
数量词的贪婪模式与非贪婪模式
正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的在少数语言里也可能是默认非贪婪总是尝试匹配尽可能多的字符非贪婪的则相反总是尝试匹配尽可能少的字符。例如
正则表达式"ab*"如果用于查找"abbbc"将找到"abbb"。而如果使用非贪婪的数量词"ab*?"将找到"a"。
反斜杠问题
与大多数编程语言相同正则表达式里使用"\"作为转义字符这就可能造成反斜杠困扰。
假如你需要匹配文本中的字符"\"那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\"前两个和后两个分别用于在编程语言里转义成反斜杠转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。
Python里的原生字符串很好地解决了这个问题这个例子中的正则表达式可以使用r"\\"表示。
同样匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串你再也不用担心是不是漏写了反斜杠写出来的表达式也更直观。
import re
a=re.search(r"\\","ab123bb\c")
print a.group()
\
a=re.search(r"\d","ab123bb\c")
print a.group()
1
Python Re模块
Python 自带了re模块它提供了对正则表达式的支持。
match函数re.match 尝试从字符串的起始位置匹配一个模式如果不是起始位置匹配成功的话match()就返回none。
下面是此函数的语法re.match(pattern, string, flags=0)
参数
描述
pattern
这是正则表达式来进行匹配。
string
这是字符串这将被搜索匹配的模式在字符串的开头。
flags
标志位用于控制正则表达式的匹配方式如是否区分大小写多行匹配等等。
匹配成功re.match方法返回一个匹配的对象否则返回None。 我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象的方法
描述
group(num=0)
此方法返回整个匹配或指定分组num
groups()
此方法返回所有元组匹配的子组空如果没有
#!/usr/bin/python
import re
line = "Cats are smarter than dogs"
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
if matchObj:
print "matchObj.group() : ", matchObj.group()
print "matchObj.group(1) : ", matchObj.group(1)
print "matchObj.group(2) : ", matchObj.group(2)
else:
print "No match!!"
当执行上面的代码它产生以下结果
matchObj.group() : Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
正则表达式修饰符 - 选项标志
正则表达式字面可以包含一个可选的修饰符来控制匹配的各个方面。修饰符被指定为一个可选的标志。可以使用异或提供多个修饰符|如先前所示并且可以由这些中的一个来表示
修饰符
描述
re.I(re.IGNORECASE)
使匹配对大小写不敏感
re.M(MULTILINE)
多行匹配影响 ^ 和 $
re.S(DOTALL)
使 . 匹配包括换行在内的所有字符
re.X(VERBOSE)
正则表达式可以是多行忽略空白字符并可以加入注释
findall()函数
re.findall(pattern, string, flags=0)
返回字符串中所有模式的非重叠的匹配作为字符串列表。该字符串扫描左到右并匹配返回的顺序发现
默认
pattren = "\w+"
target = "hello world\nWORLD HELLO"
re.findall(pattren,target)
['hello', 'world', 'WORLD', 'HELLO']
re.I:
re.findall("world", target,re.I)
['world', 'WORLD']
re.S:
re.findall("world.WORLD", target,re.S)
["world\nworld"]
re.findall("hello.*WORLD", target,re.S)
['hello world\nWORLD']
re.M:
re.findall("^WORLD",target,re.M)
["WORLD"]
re.X:
reStr = '''\d{3} #区号
-\d{8}''' #号码
re.findall(reStr,"010-12345678",re.X)
["010-12345678"]
search函数
re.search 扫描整个字符串并返回第一个成功的匹配。
下面是此函数语法re.search(pattern, string, flags=0)
参数
描述
pattern
这是正则表达式来进行匹配。
string
这是字符串这将被搜索到的字符串中的任何位置匹配的模式。
flags
标志位用于控制正则表达式的匹配方式如是否区分大小写多行匹配等等。
匹配成功re.search方法返回一个匹配的对象否则返回None。我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
#!/usr/bin/python
import re
line = "Cats are smarter than dogs";
searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
if searchObj:
print "searchObj.group() : ", searchObj.group()
print "searchObj.group(1) : ", searchObj.group(1)
print "searchObj.group(2) : ", searchObj.group(2)
else:
print "Nothing found!!"
当执行上面的代码它产生以下结果
matchObj.group() : Cats are smarter than dogs
matchObj.group(1) : Cats
matchObj.group(2) : smarter
re.match与re.search的区别
re.match只匹配字符串的开始如果字符串开始不符合正则表达式则匹配失败函数返回None而re.search匹配整个字符串直到找到一个匹配。
#!/usr/bin/python
import re
line = "Cats are smarter than dogs";
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
print "match --> matchObj.group() : ", matchObj.group()
else:
print "No match!!"
searchObj = re.search( r'dogs', line, re.M|re.I)
if searchObj:
print "search --> searchObj.group() : ", searchObj.group()
else:
print "Nothing found!!"
当执行上面的代码产生以下结果
No match!!
search --> matchObj.group() : dogs
搜索和替换
Python 的re模块提供了re.sub用于替换字符串中的匹配项。
语法re.sub(pattern, repl, string, max=0)
返回的字符串是在字符串中用 RE 最左边不重复的匹配来替换。如果模式没有发现字符将被没有改变地返回。 可选参数 count 是模式匹配后替换的最大次数count 必须是非负整数。缺省值是 0 表示替换所有的匹配。 实例
#!/usr/bin/python
import re
url = "http://hr.tencent.com/position.php?&start=10"
page = re.search('start=(\d+)',url).group(1)
nexturl = re.sub(r'start=(\d+)', 'start='+str(int(page)+10), url)
print "Next Url : ", nexturl
当执行上面的代码产生以下结果
Next Url : http://hr.tencent.com/position.php?&start=20
正则表达式语法
页面解析之结构化数据
结构化的数据是最好处理一般都是类似JSON格式的字符串直接解析JSON数据提取JSON的关键字段即可。
JSON
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式适用于进行数据交互的场景比如网站前台与后台之间的数据交互。
Python 2.7中自带了JSON模块直接import json就可以使用了。
Json模块提供了四个功能dumps、dump、loads、load,用于字符串 和 python数据类型间进行转换
Python操作json的标准api库参考 在线JSON格式化代码
1. json.loads()
实现json字符串 转化 python的类型返回一个python的类型
从json到python的类型转化对照如下
import json
a="[1,2,3,4]"
b='{"k1":1,"k2":2}'#当字符串为字典时{}外面必须是''单引号{}里面必须是""双引号
print json.loads(a)
[1, 2, 3, 4]
print json.loads(b)
{'k2': 2, 'k1': 1}
import urllib2
import json
response = urllib2.urlopen(r'http://api.douban.com/v2/book/isbn/9787218087351')
hjson = json.loads(response.read())
print hjson.keys()
print hjson['rating']
print hjson['images']['large']
print hjson['summary']
2. json.dumps()
实现python类型转化为json字符串返回一个str对象
从python原始类型向json类型的转化对照如下
import json
a = [1,2,3,4]
b ={"k1":1,"k2":2}
c = (1,2,3,4)
json.dumps(a)
'[1, 2, 3, 4]'
json.dumps(b)
'{"k2": 2, "k1": 1}'
json.dumps(c)
'[1, 2, 3, 4]'
json.dumps 中的ensure_ascii 参数引起的中文编码问题
如果Python Dict字典含有中文json.dumps 序列化时对中文默认使用的ascii编码
import chardet
import json
b = {"name":"中国"}
json.dumps(b)
'{"name": "\\u4e2d\\u56fd"}'
print json.dumps(b)
{"name": "\u4e2d\u56fd"}
chardet.detect(json.dumps(b))
{'confidence': 1.0, 'encoding': 'ascii'}
'中国' 中的ascii 字符码而不是真正的中文。想输出真正的中文需要指定ensure_ascii=False
json.dumps(b,ensure_ascii=False)
'{"name": "\xe6\x88\x91"}'
print json.dumps(b,ensure_ascii=False)
{"name": "我"}
chardet.detect(json.dumps(b,ensure_ascii=False))
{'confidence': 0.7525, 'encoding': 'utf-8'}
3. json.dump()
把Python类型 以 字符串的形式 写到文件中
import json
a = [1,2,3,4]
json.dump(a,open("digital.json","w"))
b = {"name":"我"}
json.dump(b,open("name.json","w"),ensure_ascii=False)
json.dump(b,open("name2.json","w"),ensure_ascii=True)
4. json.load()
读取 文件中json形式的字符串元素 转化成python类型
# -*- coding: utf-8 -*-
import json
number = json.load(open("digital.json"))
print number
b = json.load(open("name.json"))
print b
b.keys()
print b['name']
实战项目
获取 lagou 城市表信息
import urllib2
import json
import chardet
url ='http://www.lagou.com/lbs/getAllCitySearchLabels.json?'
request =urllib2.Request(url)
response = urllib2.urlopen(request)
print response.code
resHtml = response.read()
jsonobj = json.loads(resHtml)
print type(jsonobj)
print jsonobj
citylist =[]
allcitys = jsonobj['content']['data']['allCitySearchLabels']
print allcitys.keys()
for key in allcitys:
print type(allcitys[key])
for item in allcitys[key]:
name =item['name'].encode('utf-8')
print name,type(name)
citylist.append(name)
fp = open('city.json','w')
content = json.dumps(citylist,ensure_ascii=False)
print content
fp.write(content)
fp.close()
输出
JSONPath
JSON 信息抽取类库从JSON文档中抽取指定信息的工具
JSONPath与Xpath区别
JsonPath 对于 JSON 来说相当于 XPATH 对于XML。
下载地址https://pypi.python.org/pypi/jsonpath/
安装方法下载jsonpath解压之后执行'python setup.py install'
参考文档
XPath
JSONPath
Result
/store/book/author
$.store.book[*].author
the authors of all books in the store
//author
$..author
all authors
/store/*
$.store.*
all things in store, which are some books and a red bicycle.
/store//price
$.store..price
the price of everything in the store.
//book[3]
$..book[2]
the third book
//book[last()]
$..book[(@.length-1)]
$..book[-1:]
the last book in order.
//book[position()<3]
$..book[0,1]
$..book[:2]
the first two books
//book[isbn]
$..book[?(@.isbn)]
filter all books with isbn number
//book[price<10]
$..book[?(@.price<10)]
filter all books cheapier than 10
//*
$..*
all Elements in XML document. All members of JSON structure.
案例
还是以 http://www.lagou.com/lbs/getAllCitySearchLabels.json 为例获取所有城市
import jsonpath
import urllib2
import chardet
url ='http://www.lagou.com/lbs/getAllCitySearchLabels.json'
request =urllib2.Request(url)
response = urllib2.urlopen(request)
print response.code
resHtml = response.read()
##detect charset
print chardet.detect(resHtml)
jsonobj = json.loads(resHtml)
citylist = jsonpath.jsonpath(jsonobj,'$..name')
print citylist
print type(citylist)
fp = open('city.json','w')
content = json.dumps(citylist,ensure_ascii=False)
print content
fp.write(content.encode('utf-8'))
fp.close()
XML
xmltodict模块让使用XML感觉跟操作JSON一样
Python操作XML的第三方库参考https://github.com/martinblech/xmltodict
模块安装pip install xmltodict
import xmltodict
bookdict = xmltodict.parse("""
Harry Potter
29.99
Learning XML
39.95
""")
print bookdict.keys()
[u'bookstore']
print json.dumps(bookdict,indent=4)
输出结果
{
"bookstore": {
"book": [
{
"title": {
"@lang": "eng",
"#text": "Harry Potter"
},
"price": "29.99"
},
{
"title": {
"@lang": "eng",
"#text": "Learning XML"
},
"price": "39.95"
}
]
}
}
数据提取总结
HTML、XML
XPath
CSS选择器
正则表达式
JSON
JSONPath
转化成Python类型进行操作json类
XML
转化成Python类型xmltodict
XPath
CSS选择器
正则表达式
其他js、文本、电话号码、邮箱地址
正则表达式
- 精通网页抓取原理及技术精通正则表达式从结构化的和非结构化的数据中获取信息
- XPATH、CSS选择器、正则表达式
- 了解各种Web前端技术包括XHTML/XML/CSS/JavaScript/AJAX等
- 对目标网站进行爬取分析找到最优化的爬取策略。
json.loads的时候出错->要注意要解码的Json字符的编码
1. 如果传入的字符串的编码是基于ASCII的而不是UTF-8的话需要指定字符编码参数cencoding
对于dataDict = json.loads(dataJsonStr); 其中dataJsonStr是json字符串如果其编码本身是非UTF-8的话比如是GB2312的那么上述代码就会导致出错。改为对应的
dataDict = json.loads(dataJsonStr, encoding="GB2312");
2. 如果要解析的字符串本身的编码类型不是基于ASCII的那么调用json.loads之前需要先将对应字符串转换为Unicode类型的 还是以上述的
dataDict = json.loads(dataJsonStr, encoding="GB2312");为例即使你此处的字符串dataJsonStr已经通过encoding指定了合适的编码但是由于其中包含了其他的编码的字符比如我本身dataJsonStr是GB2312的字符但是其中又包含了的一些日文字符此时json.loads还是会出错因为此处的dataJsonStr不是以ASCII为基础的字符编码所以需要先去将dataJsonStr转换为Unicode然后再调用json.loads就可以了。
代码如下
dataJsonStrUni = dataJsonStr.decode("GB2312");
dataDict = json.loads(dataJsonStrUni, encoding="GB2312");
encode和decode区别
decode的作用是将其他编码的字符串转换成unicode编码。如str1.decode('gb2312')表示将gb2312编码的字符串str1转换成unicode编码。
encode的作用是将unicode编码转换成其他编码的字符串。如str2.encode('gb2312')表示将unicode编码的字符串str2转换成gb2312编码。
爬虫实践篇
培养解决问题的思路、编码解码的理解
解决问题的思路
如何判断需求数据在哪
A) 静态数据可通过查看网页源代码
B) 定位具体哪一个url请求抓包在Fidder里面找怎么快速定位我要的数据呢(通过Body大小除了图片之外的Http请求)
判断是什么请求方式Get还是Post
在Composer raw 模拟发送数据
A) 删除Header信息为什么删除代码简介美观、易于理解
B) 如果做翻页最好拿第二三页做测试不要用首页因为有时候第二页是Post请求而第一是静态Get请求拿第二页测试的时候返回的是第一页容易错误还不自知
参考案例Get、Post案例
写python程序
确认返回数据是什么格式的返回json还是html
A) 那如果是json呢格式化数据应该做存储 B) 那如果是html呢提取数据使用XPath、CSS选择器、正则表达式
Get和Post
1. 右键查看源代码和 F12 Elements区别 右键查看源代码实质是一个Get请求 F12 Elements是整个页面 所有的请求url 加载完成的页面
2. GET 和Post区别的方法 为什么拉钩用的Post不是表单提交密码原因是Post用户体验更好局部加载
Urlencode
urlencode()函数原理就是首先把中文字符转换为十六进制然后在每个字符前面加一个标识符%
http://www.lagou.com/jobs/list_Python?px=default&city=%E5%8C%97%E4%BA%AC&district=%E6%9C%9D%E9%98%B3%E5%8C%BA&bizArea=%E6%9C%9B%E4%BA%AC#filterBox
提出个问题中文字符按什么编码格式进行转化成十六进制呢 utf-8、gb2312、gbk urlencode编码
utf-8与utf-8 urlencode区别
import urllib
country = u'中国'
country.encode('utf-8')
'\xe4\xb8\xad\xe5\x9b\xbd'
urllib.quote(country.encode('utf-8'))
'%E4%B8%AD%E5%9B%BD'
gb2312与gb2312 urlencode区别
import urllib
country = u'中国'
country.encode('gb2312')
'\xd6\xd0\xb9\xfa'
urllib.quote(country.encode('gb2312'))
'%D6%D0%B9%FA'
案例
模拟出 拉勾网 如下url地址
http://www.lagou.com/jobs/list_Python?px=default&city=%E5%8C%97%E4%BA%AC&district=%E6%9C%9D%E9%98%B3%E5%8C%BA&bizArea=%E6%9C%9B%E4%BA%AC#filterBox
# -*- coding: utf-8 -*-
import urllib
import chardet
city=u'北京'.encode('utf-8')
district=u'朝阳区'.encode('utf-8')
bizArea=u'望京'.encode('utf-8')
query={
'city':city,
'district':district,
'bizArea':bizArea
}
print chardet.detect(query['city'])
{'confidence': 0.7525, 'encoding': 'utf-8'}
print urllib.urlencode(query)
city=%E5%8C%97%E4%BA%AC&bizArea=%E6%9C%9B%E4%BA%AC&district=%E6%9C%9B%E4%BA%AC
print 'http://www.lagou.com/jobs/list_Python?px=default&'+urllib.urlencode(query)+'#filterBox'
http://www.lagou.com/jobs/list_Python?px=default&city=%E5%8C%97%E4%BA%AC&bizArea=%E6%9C%9B%E4%BA%AC&district=%E6%9C%9B%E4%BA%AC#filterBox
模拟出 阿里巴巴 如下url地址
https://s.1688.com/selloffer/offer_search.htm?keywords=%CA%D6%BB%FA%BC%B0%C5%E4%BC%FE%CA%D0%B3%A1
# -*- coding: utf-8 -*-
import urllib
import chardet
keywords=u'手机及配件市场'.encode('gbk')
query={
'keywords':keywords,
}
print chardet.detect(query['keywords'])
{'confidence': 0.99, 'encoding': 'GB2312'}
print urllib.urlencode(query)
keywords=%CA%D6%BB%FA%BC%B0%C5%E4%BC%FE%CA%D0%B3%A1
print 'https://s.1688.com/selloffer/offer_search.htm?'+urllib.urlencode(query)
https://s.1688.com/selloffer/offer_search.htm?keywords=%CA%D6%BB%FA%BC%B0%C5%E4%BC%FE%CA%D0%B3%A1
模拟出 环球经贸网 如下url地址
http://search.nowec.com/search?q=%B0%B2%C8%AB%C3%C5
# -*- coding: utf-8 -*-
import urllib
import chardet
q=u'安全门'.encode('gb2312')
query={
'q':q,
}
print chardet.detect(query['q'])
{'confidence': 0.99, 'encoding': 'GB2312'}
print urllib.urlencode(query)
q=%B0%B2%C8%AB%C3%C5
print 'http://search.nowec.com/search?'+urllib.urlencode(query)
http://search.nowec.com/search?q=%B0%B2%C8%AB%C3%C5
采集 百度贴吧 信息
http://tieba.baidu.com/f?ie=utf-8&kw=%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB&fr=search
解决问题思路
1. 确认需求数据在哪。右键查看源代码
2. Fidder模拟发送数据
# -*- coding:utf-8 -*-
import urllib2
import urllib
from lxml import etree
import chardet
import json
import codecs
def GetTimeByArticle(url):
request = urllib2.Request(url)
response = urllib2.urlopen(request)
resHtml = response.read()
html = etree.HTML(resHtml)
time = html.xpath('//span[@class="tail-info"]')[1].text
print time
return time
def main():
output = codecs.open('tieba0812.json', 'w', encoding='utf-8')
for pn in range(0, 250, 50):
kw = u'网络爬虫'.encode('utf-8')
url = 'http://tieba.baidu.com/f?kw=' + urllib.quote(kw) + '&ie=utf-8&pn=' + str(pn)
print url
request = urllib2.Request(url)
response = urllib2.urlopen(request)
resHtml = response.read()
print resHtml
html_dom = etree.HTML(resHtml)
# print etree.tostring(html_dom)
html = html_dom
# site = html.xpath('//li[@data-field]')[0]
for site in html.xpath('//li[@data-field]'):
# print etree.tostring(site.xpath('.//a')[0])
title = site.xpath('.//a')[0].text
Article_url = site.xpath('.//a')[0].attrib['href']
reply_date = GetTimeByArticle('http://tieba.baidu.com' + Article_url)
jieshao = site.xpath('.//*[@class="threadlist_abs threadlist_abs_onlyline "]')[0].text.strip()
author = site.xpath('.//*[@class="frs-author-name j_user_card "]')[0].text.strip()
lastName = site.xpath('.//*[@class="frs-author-name j_user_card "]')[1].text.strip()
print title, jieshao, Article_url, author, lastName
item = {}
item['title'] = title
item['author'] = author
item['lastName'] = lastName
item['reply_date'] = reply_date
print item
line = json.dumps(item, ensure_ascii=False)
print line
print type(line)
output.write(line + "\n")
output.close()
print 'end'
if __name__ == '__main__':
main()
以 惠州市网上挂牌交易系统
为例http://www.hdgtjy.com/index/Index4/ 采集所有的挂牌交易信息
import urllib2
import json
fp = open('hdgtjy.json','w')
for page in range(1,28):
for i in range(5):
try:
send_headers = {'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/x-www-form-urlencoded'}
request =urllib2.Request('http://www.hdgtjy.com/Index/PublicResults',data='page='+ str(page) +'&size=10',headers=send_headers)
response = urllib2.urlopen(request)
data = response.read()
obj = json.loads(data)
print obj['data'][0]['ADDRESS']
except Exception,e:
print e
fp.write(data)
fp.close()
print 'end'
查看运行结果感受一下。
Requests基本用法与药品监督管理局
Requests
Requests 是唯一的一个非转基因的 Python HTTP 库人类可以安全享用
urllib2urllib2是python自带的模块自定义 'Connection': 'keep-alive'通知服务器交互结束后不断开连接即所谓长连接。 当然这也是urllib2不支持keep-alive的解决办法之一另一个方法是Requests。
安装 Requests
优点Requests 继承了urllib2的所有特性。Requests支持HTTP连接保持和连接池支持使用cookie保持会话支持文件上传支持自动确定响应内容的编码支持国际化的 URL 和 POST 数据自动编码。
缺陷requests不是python自带的库需要另外安装 easy_install or pip install。直接使用不能异步调用速度慢自动确定响应内容的编码。pip install requests
文档http://cn.python-requests.org/zh_CN/latest/index.html http://www.python-requests.org/en/master/#
使用方法
requests.get(url, data={'key1': 'value1'},headers={'User-agent','Mozilla/5.0'})
requests.post(url, data={'key1': 'value1'},headers={'content-type': 'application/json'})
以 药品监督管理局 为例http://app1.sfda.gov.cn/
采集分类 国产药品商品名(6994) 下的所有的商品信息
商品列表页http://app1.sfda.gov.cn/datasearch/face3/base.jsp?tableId=32&tableName=TABLE32&title=%B9%FA%B2%FA%D2%A9%C6%B7%C9%CC%C6%B7%C3%FB&bcId=124356639813072873644420336632
商品详情页http://app1.sfda.gov.cn/datasearch/face3/content.jsp?tableId=32&tableName=TABLE32&tableView=%B9%FA%B2%FA%D2%A9%C6%B7%C9%CC%C6%B7%C3%FB&Id=211315
# -*- coding: utf-8 -*-
import urllib
from lxml import etree
import re
import json
import chardet
import requests
curstart = 2
values = {
'tableId': '32',
'State': '1',
'bcId': '124356639813072873644420336632',
'State': '1',
'tableName': 'TABLE32',
'State': '1',
'viewtitleName': 'COLUMN302',
'State': '1',
'viewsubTitleName': 'COLUMN299,COLUMN303',
'State': '1',
'curstart': str(curstart),
'State': '1',
'tableView': urllib.quote("国产药品商品名"),
'State': '1',
}
post_headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
url = "http://app1.sfda.gov.cn/datasearch/face3/search.jsp"
response = requests.post(url, data=values, headers=post_headers)
resHtml = response.text
print response.status_code
# print resHtml
Urls = re.findall(r'callbackC,\'(.*?)\',null', resHtml)
for url in Urls:
# 坑
print url.encode('gb2312')
查看运行结果感受一下。
总结
1. User-Agent伪装Chrome欺骗web服务器
2. urlencode 字典类型Dict、元祖 转化成 url query 字符串
1. 完成商品详情页采集
2. 完成整个项目的采集
详情页
# -*- coding: utf-8 -*-
from lxml import etree
import re
import json
import requests
url ='http://app1.sfda.gov.cn/datasearch/face3/content.jsp?tableId=32&tableName=TABLE32&tableView=%B9%FA%B2%FA%D2%A9%C6%B7%C9%CC%C6%B7%C3%FB&Id=211315'
get_headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
'Connection': 'keep-alive',
}
item = {}
response = requests.get(url,headers=get_headers)
resHtml = response.text
print response.encoding
html = etree.HTML(resHtml)
for site in html.xpath('//tr')[1:]:
if len(site.xpath('./td'))!=2:
continue
name = site.xpath('./td')[0].text
if not name:
continue
# value =site.xpath('./td')[1].text
value = re.sub('<.*?>', '', etree.tostring(site.xpath('./td')[1],encoding='utf-8'))
item[name.encode('utf-8')] = value
json.dump(item,open('sfda.json','w'),ensure_ascii=False)
完整项目
# -*- coding: utf-8 -*-
import urllib
from lxml import etree
import re
import json
import requests
def ParseDetail(url):
# url = 'http://app1.sfda.gov.cn/datasearch/face3/content.jsp?tableId=32&tableName=TABLE32&tableView=%B9%FA%B2%FA%D2%A9%C6%B7%C9%CC%C6%B7%C3%FB&Id=211315'
get_headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
'Connection': 'keep-alive',
}
item = {}
response = requests.get(url, headers=get_headers)
resHtml = response.text
print response.encoding
html = etree.HTML(resHtml)
for site in html.xpath('//tr')[1:]:
if len(site.xpath('./td')) != 2:
continue
name = site.xpath('./td')[0].text
if not name:
continue
# value =site.xpath('./td')[1].text
value = re.sub('<.*?>', '', etree.tostring(site.xpath('./td')[1], encoding='utf-8'))
value = re.sub('', '', value)
item[name.encode('utf-8').strip()] = value.strip()
# json.dump(item, open('sfda.json', 'a'), ensure_ascii=False)
fp = open('sfda.json', 'a')
str = json.dumps(item, ensure_ascii=False)
fp.write(str + '\n')
fp.close()
def main():
curstart = 2
values = {
'tableId': '32',
'State': '1',
'bcId': '124356639813072873644420336632',
'State': '1',
'tableName': 'TABLE32',
'State': '1',
'viewtitleName': 'COLUMN302',
'State': '1',
'viewsubTitleName': 'COLUMN299,COLUMN303',
'State': '1',
'curstart': str(curstart),
'State': '1',
'tableView': urllib.quote("国产药品商品名"),
'State': '1',
}
post_headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'
}
url = "http://app1.sfda.gov.cn/datasearch/face3/search.jsp"
response = requests.post(url, data=values, headers=post_headers)
resHtml = response.text
print response.status_code
# print resHtml
Urls = re.findall(r'callbackC,\'(.*?)\',null', resHtml)
for url in Urls:
# 坑
url = re.sub('tableView=.*?&', 'tableView=' + urllib.quote("国产药品商品名") + "&", url)
ParseDetail('http://app1.sfda.gov.cn/datasearch/face3/' + url.encode('gb2312'))
if __name__ == '__main__':
main()
拉钩招聘网
以拉钩具体详情页为例进行抓取。http://www.lagou.com/jobs/2101463.html
from lxml import etree
import requests
import re
response = requests.get('http://www.lagou.com/jobs/2101463.html')
resHtml = response.text
html = etree.HTML(resHtml)
title = html.xpath('//h1[@title]')[0].attrib['title']
#salary= html.xpath('//span[@class="red"]')[0].text
salary = html.xpath('//dd[@class="job_request"]/p/span')[0].text
worklocation = html.xpath('//dd[@class="job_request"]/p/span')[1].text
experience = html.xpath('//dd[@class="job_request"]/p/span')[2].text
education = html.xpath('//dd[@class="job_request"]/p/span')[3].text
worktype = html.xpath('//dd[@class="job_request"]/p/span')[4].text
Temptation = html.xpath('//dd[@class="job_request"]/p[2]')[0].text
print salary,worklocation,experience,education,worktype,Temptation
description_tag = html.xpath('//dd[@class="job_bt"]')[0]
description = etree.tostring( description_tag,encoding='utf-8')
#print description
deal_descp = re.sub('<.*?>','',description)
print deal_descp.strip()
publisher_name = html.xpath('//*[@class="publisher_name"]//@title')[0]
pos = html.xpath('//*[@class="pos"]')[0].text
chuli_lv = html.xpath('//*[@class="data"]')[0].text
chuli_yongshi = html.xpath('//*[@class="data"]')[1].text
print chuli_lv,chuli_yongshi,pos,publisher_name
爬取糗事百科段子
确定URL并抓取页面代码,首先我们确定好页面的URL是 http://www.qiushibaike.com/8hr/page/4, 其中最后一个数字1代表页数我们可以传入不同的值来获得某一页的段子内容。我们初步构建如下的代码来打印页面代码内容试试看先构造最基本的页面抓取方式看看会不会成功。在Composer raw 模拟发送数据
GET http://www.qiushibaike.com/8hr/page/2/ HTTP/1.1
Host: www.qiushibaike.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Accept-Language: zh-CN,zh;q=0.8
在删除了User-Agent、Accept-Language报错。应该是headers验证的问题加上一个headers验证试试看
# -*- coding:utf-8 -*-
import urllib
import requests
import re
import chardet
from lxml import etree
page = 2
url = 'http://www.qiushibaike.com/8hr/page/' + str(page) + "/"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
'Accept-Language': 'zh-CN,zh;q=0.8'}
try:
response = requests.get(url, headers=headers)
resHtml = response.text
html = etree.HTML(resHtml)
result = html.xpath('//div[contains(@id,"qiushi_tag")]')
for site in result:
#print etree.tostring(site,encoding='utf-8')
item = {}
imgUrl = site.xpath('./div/a/img/@src')[0].encode('utf-8')
username = site.xpath('./div/a/@title')[0].encode('utf-8')
#username = site.xpath('.//h2')[0].text
content = site.xpath('.//div[@class="content"]')[0].text.strip().encode('utf-8')
vote = site.xpath('.//i')[0].text
#print site.xpath('.//*[@class="number"]')[0].text
comments = site.xpath('.//i')[1].text
print imgUrl, username, content, vote, comments
except Exception, e:
print e
多线程爬虫实战糗事百科
python下多线程的思考
Queue是python中的标准库可以直接import Queue引用; 队列是线程间最常用的交换数据的形式。对于共享资源加锁是个重要的环节。因为python原生的list,dict等都是not thread safe的。而Queue是线程安全的因此在满足使用条件下建议使用队列。
Python Queue模块有三种队列及构造函数:
1、Python Queue模块的FIFO队列先进先出。 class Queue.Queue(maxsize)
2、LIFO类似于堆即先进后出。 class Queue.LifoQueue(maxsize)
3、还有一种是优先级队列级别越低越先出来。 class Queue.PriorityQueue(maxsize)
Queue队列对象
初始化 class Queue.Queue(maxsize) FIFO 先进先出
包中的常用方法:
Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空返回True,反之False
Queue.full() 如果队列满了返回True,反之False
Queue.full 与 maxsize 大小对应
Queue.get([block[, timeout]])获取队列timeout等待时间
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block默认为True。
如果队列为空且block为Trueget()就使调用线程暂停直至有项目可用。
如果队列为空且block为False队列将引发Empty异常。
创建一个“队列”对象
import Queue myqueue = Queue.Queue(maxsize = 10)
将一个值放入队列中
myqueue.put(10)
将一个值从队列中取出
myqueue.get()
# -*- coding:utf-8 -*-
import requests
from lxml import etree
from Queue import Queue
import threading
import time
import json
class thread_crawl(threading.Thread):
'''
抓取线程类
'''
def __init__(self, threadID, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.q = q
def run(self):
print "Starting " + self.threadID
self.qiushi_spider()
print "Exiting ", self.threadID
def qiushi_spider(self):
# page = 1
while True:
if self.q.empty():
break
else:
page = self.q.get()
print 'qiushi_spider=', self.threadID, ',page=', str(page)
url = 'http://www.qiushibaike.com/hot/page/' + str(page) + '/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
'Accept-Language': 'zh-CN,zh;q=0.8'}
# 多次尝试失败结束、防止死循环
timeout = 4
while timeout > 0:
timeout -= 1
try:
content = requests.get(url, headers=headers)
data_queue.put(content.text)
break
except Exception, e:
print 'qiushi_spider', e
if timeout < 0:
print 'timeout', url
class Thread_Parser(threading.Thread):
'''
页面解析类
'''
def __init__(self, threadID, queue, lock, f):
threading.Thread.__init__(self)
self.threadID = threadID
self.queue = queue
self.lock = lock
self.f = f
def run(self):
print 'starting ', self.threadID
global total, exitFlag_Parser
while not exitFlag_Parser:
try:
'''
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block默认为True。
如果队列为空且block为Trueget()就使调用线程暂停直至有项目可用。
如果队列为空且block为False队列将引发Empty异常。
'''
item = self.queue.get(False)
if not item:
pass
self.parse_data(item)
self.queue.task_done()
print 'Thread_Parser=', self.threadID, ',total=', total
except:
pass
print 'Exiting ', self.threadID
def parse_data(self, item):
'''
解析网页函数
:param item: 网页内容
:return:
'''
global total
try:
html = etree.HTML(item)
result = html.xpath('//div[contains(@id,"qiushi_tag")]')
for site in result:
try:
imgUrl = site.xpath('.//img/@src')[0]
title = site.xpath('.//h2')[0].text
content = site.xpath('.//div[@class="content"]')[0].text.strip()
vote = None
comments = None
try:
vote = site.xpath('.//i')[0].text
comments = site.xpath('.//i')[1].text
except:
pass
result = {
'imgUrl': imgUrl,
'title': title,
'content': content,
'vote': vote,
'comments': comments,
}
with self.lock:
# print 'write %s' % json.dumps(result)
self.f.write(json.dumps(result, ensure_ascii=False).encode('utf-8') + "\n")
except Exception, e:
print 'site in result', e
except Exception, e:
print 'parse_data', e
with self.lock:
total += 1
data_queue = Queue()
exitFlag_Parser = False
lock = threading.Lock()
total = 0
def main():
output = open('qiushibaike.json', 'a')
#初始化网页页码page从1-10个页面
pageQueue = Queue(50)
for page in range(1, 11):
pageQueue.put(page)
#初始化采集线程
crawlthreads = []
crawlList = ["crawl-1", "crawl-2", "crawl-3"]
for threadID in crawlList:
thread = thread_crawl(threadID, pageQueue)
thread.start()
crawlthreads.append(thread)
#初始化解析线程parserList
parserthreads = []
parserList = ["parser-1", "parser-2", "parser-3"]
#分别启动parserList
for threadID in parserList:
thread = Thread_Parser(threadID, data_queue, lock, output)
thread.start()
parserthreads.append(thread)
# 等待队列清空
while not pageQueue.empty():
pass
# 等待所有线程完成
for t in crawlthreads:
t.join()
while not data_queue.empty():
pass
# 通知线程是时候退出
global exitFlag_Parser
exitFlag_Parser = True
for t in parserthreads:
t.join()
print "Exiting Main Thread"
with lock:
output.close()
if __name__ == '__main__':
main()
入坑-乱码
关于爬虫乱码有很多各式各样的问题这里不仅是中文乱码编码转换、还包括一些如日文、韩文 、俄文、藏文之类的乱码处理因为解决方式是一致的故在此统一说明。
网络爬虫出现乱码的原因源网页编码和爬取下来后的编码格式不一致。如源网页为gbk编码的字节流而我们抓取下后程序直接使用utf-8进行编码并输出到存储文件中这必然会引起乱码 即当源网页编码和抓取下来后程序直接使用处理编码一致时则不会出现乱码; 此时再进行统一的字符编码也就不会出现乱码了
注意区分源网页的编码A、程序直接使用的编码B、统一转换字符的编码C。
乱码的解决方法
确定源网页的编码A,编码A往往在网页中的三个位置
1. http header的Content-Type
获取服务器 header 的站点可以通过它来告知浏览器一些页面内容的相关信息。 Content-Type 这一条目的写法就是 "text/html; charset=utf-8"。
2. meta charset
3. 网页头中Document定义
你可能感兴趣的:(爬虫入门)
- Python爬虫入门实战:抓取CSDN博客文章
A Bug's Code Journey
爬虫python
一、前言在大数据时代,网络上充斥着海量的信息,而爬虫技术就是解锁这些信息宝库的钥匙。Python,以其简洁易读的语法和强大的库支持,成为编写爬虫的首选语言。本篇博客将从零开始,带你一步步构建一个简单的Python爬虫,抓取CSDN博客的文章标题和链接。二、环境准备在开始之前,确保你的环境中安装了Python和以下必要的库:1.requests:用于发送HTTP请求2.BeautifulSoup:用
- 爬虫入门教程:爬虫概述
会三十六变的猫
爬虫爬虫python大数据
在数字化时代,数据已经成为我们生活和工作中不可或缺的一部分。而如何高效、准确地获取这些数据,成为了许多领域面临的共同问题。今天,我们就来一起探讨一下爬虫技术,这个能够自动从互联网上抓取信息的神奇工具。一、什么是爬虫简单来说,爬虫(WebCrawler)是一种按照一定规则,自动抓取互联网信息的程序或者脚本。它通过模拟人类浏览器的行为,向目标网站发送请求,然后解析并提取返回的数据。这些数据可以是网页的
- 2024年Python最新Python爬虫入门教程30:爬取拉勾网招聘数据信息(1)
2401_84584609
程序员python爬虫信息可视化
Python爬虫入门教程23:A站视频的爬取,解密m3u8视频格式Python爬虫入门教程24:下载某网站付费文档保存PDFPython爬虫入门教程25:绕过JS加密参数,实现批量下载抖某音无水印视频内容Python爬虫入门教程26:快手视频网站数据内容下载Python爬虫入门教程27:爬取某电商平台数据内容并做数据可视化Python爬虫入门教程28:爬取微博热搜榜并做动态数据展示Python爬虫
- 爬虫入门学习---爬取搜狗网页数据
DHPYX
python爬虫爬虫pythonpycharm
什么是爬虫:通过编写程序,模拟浏览器上网,然后让其去互联网抓取数据的过程我用的是pycharm中的requests模块来实现步骤如下:目录步骤如下:代码如下#step1:指定url#step2:发起请求#step3:获取响应数据,text返回的是字符串形式的响应数据#step4:持久化存储代码如下#需求:爬取搜狗首页数据importrequests#step1:指定urlurl='https://
- 爬虫入门学习
yogurt=b
数据分析爬虫学习python
流程获取网页内容HTTP请求PythonRequests解析网页内容HTML网页结构PythonBeautifulSoup储存或分析数据HTTP(HypertextTransferProtocol)客户端和服务器之间的请求-响应协议Get方法:获得数据POST方法:创建数据HTTP请求请求行方法类型资源路径?查询参数协议版本POST/user/info?new_user=true&…HTTP/1.
- Python爬虫入门
ma_no_lo
Python网络爬虫python爬虫开发语言数据挖掘scrapy
一,爬虫概述网络爬虫,顾名思义,它是一种顺着url爬取网页数据的自动化程序或者脚本。可以认为地,我们给予爬虫一个网站的url,它就会返回给我们网站的源代码,我们通过正则表达式来筛选我们需要的内容数据,这就是爬虫的目的,而所谓的反爬和反反爬策略只是这个过程的障碍与应对。反爬机制:门户网站对爬虫的应对策略,防止爬虫对网站的数据进行爬取。反反爬策略:对反爬机制的应对策略Robots.txt:该文件规定了
- 【爬虫入门知识讲解:正则表达式】
无敌开心
爬虫正则表达式
正则表达式RegularExpression,译作正则表达式或正规表示法,表示有规则的表达式,意思是说,描述一段文本排列规则的表达式。正则表达式并不是Python的一部分。而是一套独立于编程语言,用于处理复杂文本信息的强大的高级文本操作工具。正则表达式拥有自己独特的规则语法以及一个独立的正则处理引擎,我们根据正则语法编写好规则(模式)以后,引擎不仅能够根据规则进行模糊文本查找,还可以进行模糊分割,
- python爬虫入门篇——正则表达式
rds.
爬虫正则表达式python
上一篇爬虫入门文章:python爬虫——入门python爬虫入门—正则表达式前面的话正则表达式是干什么的?一、正则表达式的概念二、正则表达式的语法三、Re库的基本使用3.1基本使用3.2Re库的match对象3.3Re库的贪婪匹配,最小匹配前面的话声明:由于本文拒绝以任何形式进行盈利,仅供学习研究使用!转载请注明文章来源。对于爬虫本身的安全问题:用于个人使用或科研范畴,基本不存在问题。数据用于商业
- 爬虫入门:正则表达式
T2020_2_22
正则表达式python
正则表达式1.又称规则表达式(英语:RegularExpression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。2.是对字符串操作的一种逻辑公式。用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正则表达式的作用用来检测用户的输入是
- Python 爬虫入门(十二):正则表达式「详细介绍」
blues_C
Python爬虫实战python爬虫正则表达式
Python爬虫入门(十二):正则表达式前言一、正则表达式的用途二、正则表达式的基本组成元素2.1特殊字符2.2量词2.3位置锚点2.4断言2.5字符集2.6字符类2.6.1基本字符类2.6.2常见字符类简写2.6.3POSIX字符类2.6.4组合使用三、正则表达式语法规则四、高级特性4.1回溯引用(捕获组)示例:匹配重复的单词4.2非捕获组示例:非捕获组的使用4.3贪婪与非贪婪匹配示例:贪婪与非
- Python爬虫入门教程(非常详细)_python爬虫自学
rr8f2haQf
python爬虫javascript
设k值为3,即每抓取3个页面后,重新计算一次PageRank值。已知有{1,2,3}这3个网页下载到本地,这3个网页包含的链接指向待下载网页{4,5,6}(即待抓取URL队列),此时将这6个网页形成一个网页集合,对其进行PageRank值的计算,则{4,5,6}每个网页得到对应的PageRank值,根据PageRank值从大到小排序,由图假设排序结果为5,4,6,当网页5下载后,分析其链接发现指向
- python爬虫入门
一点流水~
爬虫python开发语言
一、首先需要了解爬虫的原理爬虫就是一个自动化数据采集工作,你只需要告诉它需要采取哪些数据,给它一个url,就可以自动的抓取数据。其背后的基本原理就是爬虫模拟浏览器向目标服务器发送http请求,然后目标服务器返回响应结果,爬虫客户端收到响应并从中提取数据,再进行数据清洗、数据存储工作。二、爬虫的基本流程爬虫的基本流程与访问浏览器类似,就是建立一个http请求,当用户输入一个url之后,点击确认,客户
- 普通人如何开启真正的赚钱之路
码农飞哥
副业探索副业个人IP赚钱
您好,我是码农飞哥(wei158556),感谢您阅读本文,欢迎一键三连哦。1.Python基础专栏,基础知识一网打尽,9.9元买不了吃亏,买不了上当。Python从入门到精通2.毕业设计专栏,毕业季咱们不慌忙,几百款毕业设计等你选。❤️3.Python爬虫专栏,系统性的学习爬虫的知识点。9.9元买不了吃亏,买不了上当。python爬虫入门进阶❤️4.Ceph实战,从原理到实战应有尽有。Ceph实战
- 网络爬虫入门
木安`
爬虫技术爬虫网络协议程序人生开源pycharm
本章从网络爬虫概述入手,介绍网络爬虫的相关基础知识,包括网络爬虫的原理、分类和应用,网络爬虫工作流程,网络爬虫协议,以及搭建Python开发环境等内容目录1网络爬虫概述2网络爬虫工作流程3网络爬虫协议4搭建Python开发环境1网络爬虫概述网络爬虫又称为“网络蜘蛛”,是一个用来实现自动采集网络数据的程序。如果将互联网比作一张蜘蛛网,互联网上的一个个网页比作蜘蛛网上的一个个节点,那么网页与网页之间的
- 32个Python爬虫项目。
Nazarite_0141
今天为大家整理了32个Python爬虫项目。整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心。所有链接指向GitHub,祝大家玩的愉快~O(∩_∩)OWechatSogou[1]-微信公众号爬虫。基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫,返回结果是列表,每一项均是公众号具体信息字典。DouBanSpider[2]-豆瓣读书爬虫。可以爬下豆瓣读书标签下的所有
- 必须收藏!23个Python爬虫开源项目代码:微信、淘宝、等
python588
pythonpythonjava大数据数据库github
今天分享的文章为大家整理了23个Python爬虫项目。整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心,所有链接指向GitHub,微信不能直接打开,老规矩,可以用电脑打开。.1.WechatSogou–微信公众号爬虫基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫,返回结果是列表,每一项均是公众号具体信息字典。github地址:https://github.com
- 23个Python爬虫开源项目代码:爬取微信、淘宝、豆瓣、知乎、微博
「已注销」
pythonjava大数据数据库搜索引擎
今天为大家整理了32个Python爬虫项目。整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心,所有链接指向GitHub。1、WechatSogou–微信公众号爬虫基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫,返回结果是列表,每一项均是公众号具体信息字典。github地址:https://github.com/Chyroc/WechatSogou2、DouBan
- 23个Python爬虫开源项目代码:微信、淘宝、豆瓣、知乎、微博...
互联网架构
python编程语言搜索引擎大数据java
来源:Python数据科学今天为大家整理了23个Python爬虫项目。整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心,所有链接指向GitHub,微信不能直接打开,老规矩,可以用电脑打开。1.WechatSogou–微信公众号爬虫基于搜狗微信搜索的微信公众号爬虫接口,可以扩展成基于搜狗搜索的爬虫,返回结果是列表,每一项均是公众号具体信息字典。github地址:https://git
- Python---python网络爬虫入门实践总结
maidu_xbd
Python
目录一、爬虫介绍二、利用urllib实现最小的爬虫程序三、Requests爬虫实现四、数据解析利器:lxmlxpath五、selenium+chromeDriver一、爬虫介绍爬虫:网络数据采集的程序。爬虫爬取的数据有什么用?(1)资料库(2)数据分析(3)人工智能:人物画像;推荐系统:今日头条、亚马逊等;图像识别;自然语言处理为什么用python写爬虫?java:代码量很大,重构成本变大。php
- node爬虫入门竟如此简单
南宫__
前言爬虫一直是软件工程师里看起来比较神秘高深的一门学问,它让人们想起黑客,以及SEO等等。目前市面上也有专门的爬虫工程师,并且在大企业的大数据部门,大数据工程师们也会兼任一些爬取竞对数据的工作,当然也有专门做安全的工程师应对爬虫的危害。所以爬虫真的那么高深莫测吗?下面就来揭开它的神秘面纱,带你入门node爬虫!我们的目标是:爬取链家官网租房市场相关数据,并形成可视化图表最终成果在这之前,我们先普及
- 爬虫入门概念
大码农丿
爬虫爬虫python
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、爬虫是什么?二、爬虫的分类1.Robots协议2.爬虫基本流程3、request4、response能抓取怎么样的数据总结前言出一系列爬虫入门文章,不断更新!提示:以下是本篇文章正文内容,下面案例可供参考一、爬虫是什么?爬虫简单来说就是通过代码实现自动化脚本,对网页深度信息进行自动提取。二、爬虫的分类根据使用场景,网络
- python爬虫入门(一)
万年枝
python爬虫开发语言
使用requests库获取网站html信息importrequestsresponse=requests.get("https://jingyan.baidu.com/article/17bd8e52c76b2bc5ab2bb8a2.html#:~:text=1.%E6%89%93%E5%BC%80%E6%B5%8F%E8%A7%88%E5%99%A8F12%202.%E6%89%BE%E5%88
- Python网络爬虫入门基础 _反爬虫【4】
tiamo_16
Python网络爬虫网络编程python爬虫开发语言网络安全
1.由于网络爬虫具有一定的弊端,使用网络爬虫可以悄无声息的从互联网上获取很多资源,包括一些付费,原创和不公开的资源。所以很多大型网站都采取了反爬虫机制,来抵御爬虫的不正当行为。2.本次介绍了什么是反网络爬虫?,简单的爬虫伪装操作?以及如何应对网络爬虫?。什么是反网络爬虫?反爬虫:**是指对扫描器中的网络爬虫环节进行反制,它会根据ip访问频率,浏览网页速度和User-Agent等参数来判断是否为网络
- 爬虫入门到精通_基础篇2(Requests库_get请求,POST请求,文件上传,获取cookie,会话维持,证书验证, 代理设置,超时设置,认证设置,异常处理)
好奇养活小猫
爬虫
1什么是RequestsRequests是用Python语言编写,基于urllib,采用Apache2Licensed开源协议的HTTP库。它比urllib更加方便,可以节约我们大量的工作,完全满足HTTP测试需求。一句话——python实现的简单易用的HTTP库。2requests1.安装pip3installrequests2.实例引入importrequestsresponse=reques
- 爬虫入门到精通_基础篇4(BeautifulSoup库_解析库,基本使用,标签选择器,标准选择器,CSS选择器)
好奇养活小猫
#爬虫爬虫beautifulsoupcss
1Beautiful说明BeautifulSoup库是灵活又方便的网页解析库,处理高效,支持多种解析器。利用它不用编写正则表达式即可方便地实线网页信息的提取。安装pip3installbeautifulsoup4解析库解析器使用方法优势劣势Python标准库BeautifulSoup(markup,“html.parser”)Python的内置标准库、执行速度适中、文档容错能力强Python2.7
- 如何让爬虫更快
高金01
本文章属于爬虫入门到精通系统教程第十一讲在前面的教程中,我们已经学会了如何抓取一个网页,可是,当我需要抓取的数据足够多的时候,应该如何让我抓取的速度更快呢?最简单的方法就是使用多进程.什么是多线程多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。使用多线程的好处使用
- 爬虫入门到精通_基础篇3(正则表达式基础_常用的匹配规则,re.match,re.search,re.findall,re.sub,re.compile)
好奇养活小猫
#爬虫爬虫正则表达式
1什么是正则表达式正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符,及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一种过滤逻辑。非Python独有,re模块实现在线正则表达式测试右侧是常用的正则表达式,可以从待匹配的文本中匹配到相应的结果常用的匹配规则模式描述\w匹配字母,数字及下划线\W匹配不是字母,数字及下划线的字符\s匹配任意空白字符
- 【Python爬虫入门到精通】小白也能看懂的知识要点与学习路线
吴秋霖
Python爬虫实战python爬虫学习
文章目录1.写在前面2.爬虫行业情况3.学习路线【作者主页】:吴秋霖【作者介绍】:Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作!【作者推荐】:对JS逆向感兴趣的朋友可以关注《爬虫JS逆向实战》,对分布式爬虫平台感兴趣的朋友可以关注《分布式爬虫平台搭建与开发实战》还有未来会持续更新的验证码突防、APP逆向、Python领域等一系列文章1.写
- 四步带你爬虫入门,手把手教学爬取电影数据
HuDragonYu
爬虫python开发语言
本文内容是通过Pycharm来进行实操一、搭建虚拟环境创建项目的虚拟环境,目的是为了不让其他的环境资源干扰到当前的项目二、创建项目本文将以豆瓣作为手把手学习参考,网址:https://movie.douban.com/top250,1.进入Terminal终端,安装我们需要的scrapy模块pipinstallscrapy2.通过pycharm进入Terminal终端,输入我们接下来打算创建的项目
- 网页的解析之正则表达式
高金01
在爬虫入门到精通第四讲中,我们了解了如何下载网页,这一节就是如何从下载的网页中获取我们想要的内容html=u"""文章的标题h1文字Input"""我们要获取的html如上所示假如我们要获取文章的标题这几个文字,那么我们应该怎么做呢?我们只要能定位到它,也就能获取到它那么,如何定位到它呢?很简单,根据它两边的内容.我们很简单的能发现它左边是,右边是所以,我们如何找到文章的标题这几个文字呢,只要左边
- js动画html标签(持续更新中)
843977358
htmljs动画mediaopacity
1.jQuery 效果 - animate() 方法 改变 "div" 元素的高度: $(".btn1").click(function(){ $("#box").animate({height:"300px
- springMVC学习笔记
caoyong
springMVC
1、搭建开发环境
a>、添加jar文件,在ioc所需jar包的基础上添加spring-web.jar,spring-webmvc.jar
b>、在web.xml中配置前端控制器
<servlet>
&nbs
- POI中设置Excel单元格格式
107x
poistyle列宽合并单元格自动换行
引用:http://apps.hi.baidu.com/share/detail/17249059
POI中可能会用到一些需要设置EXCEL单元格格式的操作小结:
先获取工作薄对象:
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet();
HSSFCellStyle setBorder = wb.
- jquery 获取A href 触发js方法的this参数 无效的情况
一炮送你回车库
jquery
html如下:
<td class=\"bord-r-n bord-l-n c-333\">
<a class=\"table-icon edit\" onclick=\"editTrValues(this);\">修改</a>
</td>"
j
- md5
3213213333332132
MD5
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MDFive {
public static void main(String[] args) {
String md5Str = "cq
- 完全卸载干净Oracle11g
sophia天雪
orale数据库卸载干净清理注册表
完全卸载干净Oracle11g
A、存在OUI卸载工具的情况下:
第一步:停用所有Oracle相关的已启动的服务;
第二步:找到OUI卸载工具:在“开始”菜单中找到“oracle_OraDb11g_home”文件夹中
&
- apache 的access.log 日志文件太大如何解决
darkranger
apache
CustomLog logs/access.log common 此写法导致日志数据一致自增变大。
直接注释上面的语法
#CustomLog logs/access.log common
增加:
CustomLog "|bin/rotatelogs.exe -l logs/access-%Y-%m-d.log 
- Hadoop单机模式环境搭建关键步骤
aijuans
分布式
Hadoop环境需要sshd服务一直开启,故,在服务器上需要按照ssh服务,以Ubuntu Linux为例,按照ssh服务如下:
sudo apt-get install ssh
sudo apt-get install rsync
编辑HADOOP_HOME/conf/hadoop-env.sh文件,将JAVA_HOME设置为Java
- PL/SQL DEVELOPER 使用的一些技巧
atongyeye
javasql
1 记住密码
这是个有争议的功能,因为记住密码会给带来数据安全的问题。 但假如是开发用的库,密码甚至可以和用户名相同,每次输入密码实在没什么意义,可以考虑让PLSQL Developer记住密码。 位置:Tools菜单--Preferences--Oracle--Logon HIstory--Store with password
2 特殊Copy
在SQL Window
- PHP:在对象上动态添加一个新的方法
bardo
方法动态添加闭包
有关在一个对象上动态添加方法,如果你来自Ruby语言或您熟悉这门语言,你已经知道它是什么...... Ruby提供给你一种方式来获得一个instancied对象,并给这个对象添加一个额外的方法。
好!不说Ruby了,让我们来谈谈PHP
PHP未提供一个“标准的方式”做这样的事情,这也是没有核心的一部分...
但无论如何,它并没有说我们不能做这样
- ThreadLocal与线程安全
bijian1013
javajava多线程threadLocal
首先来看一下线程安全问题产生的两个前提条件:
1.数据共享,多个线程访问同样的数据。
2.共享数据是可变的,多个线程对访问的共享数据作出了修改。
实例:
定义一个共享数据:
public static int a = 0;
- Tomcat 架包冲突解决
征客丶
tomcatWeb
环境:
Tomcat 7.0.6
win7 x64
错误表象:【我的冲突的架包是:catalina.jar 与 tomcat-catalina-7.0.61.jar 冲突,不知道其他架包冲突时是不是也报这个错误】
严重: End event threw exception
java.lang.NoSuchMethodException: org.apache.catalina.dep
- 【Scala三】分析Spark源代码总结的Scala语法一
bit1129
scala
Scala语法 1. classOf运算符
Scala中的classOf[T]是一个class对象,等价于Java的T.class,比如classOf[TextInputFormat]等价于TextInputFormat.class
2. 方法默认值
defaultMinPartitions就是一个默认值,类似C++的方法默认值
- java 线程池管理机制
BlueSkator
java线程池管理机制
编辑
Add
Tools
jdk线程池
一、引言
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
- 关于hql中使用本地sql函数的问题(问-答)
BreakingBad
HQL存储函数
转自于:http://www.iteye.com/problems/23775
问:
我在开发过程中,使用hql进行查询(mysql5)使用到了mysql自带的函数find_in_set()这个函数作为匹配字符串的来讲效率非常好,但是我直接把它写在hql语句里面(from ForumMemberInfo fm,ForumArea fa where find_in_set(fm.userId,f
- 读《研磨设计模式》-代码笔记-迭代器模式-Iterator
bylijinnan
java设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
import java.util.Arrays;
import java.util.List;
/**
* Iterator模式提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象内部表示
*
* 个人觉得,为了不暴露该
- 常用SQL
chenjunt3
oraclesqlC++cC#
--NC建库
CREATE TABLESPACE NNC_DATA01 DATAFILE 'E:\oracle\product\10.2.0\oradata\orcl\nnc_data01.dbf' SIZE 500M AUTOEXTEND ON NEXT 50M EXTENT MANAGEMENT LOCAL UNIFORM SIZE 256K ;
CREATE TABLESPA
- 数学是科学技术的语言
comsci
工作活动领域模型
从小学到大学都在学习数学,从小学开始了解数字的概念和背诵九九表到大学学习复变函数和离散数学,看起来好像掌握了这些数学知识,但是在工作中却很少真正用到这些知识,为什么?
最近在研究一种开源软件-CARROT2的源代码的时候,又一次感觉到数学在计算机技术中的不可动摇的基础作用,CARROT2是一种用于自动语言分类(聚类)的工具性软件,用JAVA语言编写,它
- Linux系统手动安装rzsz 软件包
daizj
linuxszrz
1、下载软件 rzsz-3.34.tar.gz。登录linux,用命令
wget http://freeware.sgi.com/source/rzsz/rzsz-3.48.tar.gz下载。
2、解压 tar zxvf rzsz-3.34.tar.gz
3、安装 cd rzsz-3.34 ; make posix 。注意:这个软件安装与常规的GNU软件不
- 读源码之:ArrayBlockingQueue
dieslrae
java
ArrayBlockingQueue是concurrent包提供的一个线程安全的队列,由一个数组来保存队列元素.通过
takeIndex和
putIndex来分别记录出队列和入队列的下标,以保证在出队列时
不进行元素移动.
//在出队列或者入队列的时候对takeIndex或者putIndex进行累加,如果已经到了数组末尾就又从0开始,保证数
- C语言学习九枚举的定义和应用
dcj3sjt126com
c
枚举的定义
# include <stdio.h>
enum WeekDay
{
MonDay, TuesDay, WednesDay, ThursDay, FriDay, SaturDay, SunDay
};
int main(void)
{
//int day; //day定义成int类型不合适
enum WeekDay day = Wedne
- Vagrant 三种网络配置详解
dcj3sjt126com
vagrant
Forwarded port
Private network
Public network
Vagrant 中一共有三种网络配置,下面我们将会详解三种网络配置各自优缺点。
端口映射(Forwarded port),顾名思义是指把宿主计算机的端口映射到虚拟机的某一个端口上,访问宿主计算机端口时,请求实际是被转发到虚拟机上指定端口的。Vagrantfile中设定语法为:
c
- 16.性能优化-完结
frank1234
性能优化
性能调优是一个宏大的工程,需要从宏观架构(比如拆分,冗余,读写分离,集群,缓存等), 软件设计(比如多线程并行化,选择合适的数据结构), 数据库设计层面(合理的表设计,汇总表,索引,分区,拆分,冗余等) 以及微观(软件的配置,SQL语句的编写,操作系统配置等)根据软件的应用场景做综合的考虑和权衡,并经验实际测试验证才能达到最优。
性能水很深, 笔者经验尚浅 ,赶脚也就了解了点皮毛而已,我觉得
- Word Search
hcx2013
search
Given a 2D board and a word, find if the word exists in the grid.
The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or ve
- Spring4新特性——Web开发的增强
jinnianshilongnian
springspring mvcspring4
Spring4新特性——泛型限定式依赖注入
Spring4新特性——核心容器的其他改进
Spring4新特性——Web开发的增强
Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC
Spring4新特性——Groovy Bean定义DSL
Spring4新特性——更好的Java泛型操作API
Spring4新
- CentOS安装配置tengine并设置开机启动
liuxingguome
centos
yum install gcc-c++
yum install pcre pcre-devel
yum install zlib zlib-devel
yum install openssl openssl-devel
Ubuntu上可以这样安装
sudo aptitude install libdmalloc-dev libcurl4-opens
- 第14章 工具函数(上)
onestopweb
函数
index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/
- Xelsius 2008 and SAP BW at a glance
blueoxygen
BOXelsius
Xelsius提供了丰富多样的数据连接方式,其中为SAP BW专属提供的是BICS。那么Xelsius的各种连接的优缺点比较以及Xelsius是如何直接连接到BEx Query的呢? 以下Wiki文章应该提供了全面的概览。
http://wiki.sdn.sap.com/wiki/display/BOBJ/Xcelsius+2008+and+SAP+NetWeaver+BW+Co
- oracle表空间相关
tongsh6
oracle
在oracle数据库中,一个用户对应一个表空间,当表空间不足时,可以采用增加表空间的数据文件容量,也可以增加数据文件,方法有如下几种:
1.给表空间增加数据文件
ALTER TABLESPACE "表空间的名字" ADD DATAFILE
'表空间的数据文件路径' SIZE 50M;
&nb
- .Net framework4.0安装失败
yangjuanjava
.netwindows
上午的.net framework 4.0,各种失败,查了好多答案,各种不靠谱,最后终于找到答案了
和Windows Update有关系,给目录名重命名一下再次安装,即安装成功了!
下载地址:http://www.microsoft.com/en-us/download/details.aspx?id=17113
方法:
1.运行cmd,输入net stop WuAuServ
2.点击开