tsvico的博客

好的代码像粥一样,都是用时间熬出来的

python爬虫入门到进阶(二)

前言

用python发送一个请求

获取百度首页源码

打开了我的IDEA

接上一篇 入门到放弃一

本文用到的是python2.7版本

浏览器的一次请求,输入url到地址栏、回车

最后返回一个网页,在请求方式来讲,这是一种get请求

在一次请求发送中

image

可以看到还向www.baidu.com发送了User-Agent(简称UA),Host,cookie等数据

我们使用模拟请求工具访问

image

可以看到返回的数据实际上时HTML代码,只是自动被浏览器解析后才变成了我们看到的网页

下面我们提出第一个问题

爬虫是什么

如果我们把互联网比作一张大的蜘蛛网,数据便是存放于蜘蛛网的各个节点,而爬虫就是一只小蜘蛛,沿着网络抓取自己的猎物(数据)爬虫指的是:向网站发起请求,获取资源后分析并提取有用数据的程序;

从技术层面来说就是 通过程序模拟浏览器请求站点的行为,把站点返回的HTML代码/JSON数据/二进制数据(图片、视频) 爬到本地,进而提取自己需要的数据,存放起来使用;

爬虫的流程是什么

从一个普通用户的角度来看,获取网络内容的方式应该是:

浏览器提交请求—–>下载网页代码—–>浏览器把代码解析成界面

爬虫要做的就应该是:

模拟浏览器(非浏览器)请求—–>获取数据—–>解析代码数据提取有效信息—–>存储

这么比较是不是爬虫就简单多了

发起请求

使用http库向目标站点发起请求,即发送一个Request

Request包含:请求头、请求体等

Request模块缺陷:不能执行JS 和CSS 代码

获取响应内容

如果服务器能正常响应,则会得到一个Response

Response包含:html,json,图片,视频等

解析内容

解析html数据:正则表达式(RE模块),第三方解析库如Beautifulsoup,pyquery等

解析json数据:json模块

解析二进制数据:以wb的方式写入文件

保存数据

数据库(MySQL,Mongdb、Redis)

文件

请求的数据包

请求方式

GET、HEAD、PUT、DELETE、POST、OPTIONS
最常用的GET/POST

GET:GET可以说是最常见的,它本质就是发送一个请求来获取服务器上的某一资源。资源通过一组HTTP头和呈现数据(如HTML文本,或者图片或者视频等等)返回给客户端。GET请求中不会包含呈现数据。

POST:向服务器提交数据。这个方法用途广泛,几乎所有的提交操作都是靠这个完成。

如果你想了解更多,左手google,右手百度 这里不做过多解释

请求的目标

URL,又叫全球统一资源定位符,每个资源的URL都是唯一的

例如 https://www.baidu.com/s?ie=UTF-8&wd=%E5%9B%BE%E7%89%87

‘wd=’之后的一堆字符,其实是‘图片’两个中文被编码后的数据

请求头

User-agent:请求头中如果没有user-agent客户端配置,服务端可能将你当做一个非法用户host;cookies:cookie用来保存登录信息

一般做爬虫都会加上请求头,Cookie看目标网站的具体要求,可能还会需要一些其他头

Referrer:访问源至哪里来

User-Agent:访问的浏览器

请求体

GET方式没有请求体,所有的数据都在URL中

响应状态码

200:代表成功

301:代表跳转

404:文件不存在

403:无权限访问

502:服务器错误

正文

初体验

怎么爬取一个网页呢,换句话说怎么才能获取到一个网站的数据呢

1
2
3
import urllib2
response = urllib2.urlopen("http://www.baidu.com")
print response.read()

没错除去第一行引入,真正的代码只有两行

如果此时你没有安装IDE,那么用文本编辑器将上面内容保存成test1.py

一定要自己亲自打一下代码

运行

1
python test1.py

image

后面会讲我的代码为什么多了一行

分析源码

第一行

1
response = urllib2.urlopen("http://www.baidu.com")

这里我们调用了urllib2库的urlopen方法,urlopen有三个参数,如下:

1
urlopen(url,data,timeout)

第一个参数url上面我们说过了,第二个参数是访问url时要传入的数据,第三个为超时设置(超时放弃访问)

第二三个参数可以为空,data默认为空None,timeout默认为 socket._GLOBAL_DEFAULT_TIMEOUT

第一个参数是必须的,返回的值存在=左侧的变量中,存储的是response对象 打印:

1
print response.read()

response对象有个read()方法,可以返回获取的内容,如果我们不加read直接打印会怎么样

image

直接打印出了该对象的描述

构造Request

urlopen参数可以传入一个request请求,它本身就是一个Request类的实例,现在我们来填一下上边挖的坑,我的代码为什么多了一行

1
2
3
4
import urllib2
request = urllib2.Request("http://www.baidu.com")
response = urllib2.urlopen(request)
print response.read()

这就是中间构造了一个Request对象,运行结果一致,但是推荐这种写法

POST和GET数据传送

前边提到了6中请求方式,最常用的有post和get

很多时候我们获取数据还要进行参数的提交,例如模拟登陆,post方式会发送数据包,而get方式则会把数据放在要访问的url中

POST方式:

上面我们说了data参数是干嘛的?对了,它就是用在这里的,我们传送的数据就是这个参数data,下面演示一下POST方式。

1
2
3
4
5
6
7
8
import urllib
import urllib2
values = {"username":"xxx","password":"XXXX"}
data = urllib.urlencode(values)
url = "https://passport.csdn.net/account/login?from=http://my.csdn.net/my/mycsdn"
request = urllib2.Request(url,data)
response = urllib2.urlopen(request)
print response.read()

我们引入了urllib库,现在我们模拟登陆CSDN,当然上述代码可能登陆不进去,因为CSDN还有个流水号的字段,没有设置全,比较复杂在这里就不写上去了,在此只是说明登录的原理。一般的登录网站一般是这种写法。

我们需要定义一个字典,名字为values,参数我设置了username和password,下面利用urllib的urlencode方法将字典编码,命名为data,构建request时传入两个参数,url和data,运行程序,返回的便是POST后呈现的页面内容。

注意上面字典的定义方式还有一种,下面的写法是等价的

1
2
3
4
5
6
7
8
9
10
import urllib
import urllib2
values = {}
values['username'] = "xxx"
values['password'] = "XXXX"
data = urllib.urlencode(values)
url = "http://passport.csdn.net/account/login?from=http://my.csdn.net/my/mycsdn"
request = urllib2.Request(url,data)
response = urllib2.urlopen(request)
print response.read()

以上方法便实现了POST方式的传送

GET方式:

至于GET方式我们可以直接把参数写到网址上面,直接构建一个带参数的URL出来即可。

1
2
3
4
5
6
7
8
9
10
11
import urllib
import urllib2
values={}
values['username'] = "xxx"
values['password']="XXXX"
data = urllib.urlencode(values)
url = "http://passport.csdn.net/account/login"
geturl = url + "?"+data
request = urllib2.Request(geturl)
response = urllib2.urlopen(request)
print response.read()

你可以print geturl,打印输出一下url,发现其实就是原来的url加?然后加编码后的参数

1
http://passport.csdn.net/account/login?username=xxx&password=XXXX

和我们平常GET访问方式一模一样,这样就实现了数据的GET方式传送。

上边是我在网上找的一个例子,登不上的…你可以自己找个网站,获取源码尝试登陆一下

下一节 带请求头的访问

坚持原创技术分享,您的支持将鼓励我继续创作!