R语言爬虫系列3|HTTP协议
要想使用R语言从网络抓取数据,我们就必须对R语言进行设置使得R具备与服务器及Web服务进行通信的能力。而互联网中进行网络通信的通用语言就是HTTP(HypterText Transfer Protocol),即所谓超文本传输协议。那这个超文本传输协议是个什么东西呢?
超文本协议是一种用于分布式、协作式和超媒体信息系统的应用层协议,是一个客户端终端(用户)和服务器终端(网站)请求和应答的标准(TCP),通过使用网页浏览器、网络爬虫或者其他工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80)来获取网络资源的过程。说人话HTTP就是浏览器或者爬虫工具如何来接收网页HTML的方法。
实际生活中,当我们坐在电脑前,用浏览器访问淘宝进行购物,其间我们基本上不会与HTTP打交道。创建和发送HTTP请求以及处理服务器端返回的HTTP响应都是由浏览器一手搞定,试想一下如果大家每次用淘宝购物都需要手动构建类似“用HTTP协议把www.taobao.com网页下的某个商品链接传递给我”这样的请求,岂不是非常坑爹?虽然很坑爹,但我们现在需要用R语言来做一次,看看R在进行爬虫时如何来模拟浏览器和网络通信的任务。为了满足我们多样的爬虫需求,我们必须深入学习一下网络中文件传输协议并准确构建请求。
访问NBA中文网主页
louwill先给大家看一个在访问NBA中文网主页的时候浏览器是如何通过HTTP协议帮我们构建请求以及服务器是如何相应我们的请求的。在这个例子中,我们首先建立了到http://china.nba.com/的连接,并请求服务器发送index.html。HTTP客户端首先把主机翻译为一个IP地址并在缺省的HTTP端口(80端口)建立到服务器的连接。打个比方说,这个80端口就好比网络资源服务器所在的屋子的门,HTTP客户端就是通过敲正门来建立起连接的,相应的请求和响应过程总结如下:
客户端会话信息:
About to connect() to china.nba.com port 80 (#0)
Trying 127.0.0.1:50049... connected
Connected to china.nba.com(127.0.0.1:50049) port 80 (#0)
Connected #0 to host china.nba.com left intact
建立连接之后,服务器会等待请求,浏览器会向服务器发送如下的HTTP请求:
GET /index.html HTTP/1.1
Host: china.nba.com
Accept: text/html,application/xhtml+xml,application/xml;
q=0.9,image/webp,*/*;q=0.8
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36
(KHTML, like Gecko)Chrome/49.0.2623.221 Safari/537.36 SE
2.X MetaSr 1.0
然后就是服务器该如何响应浏览器的请求了:
HTTP/1.1 200 OK
Date:Thu, 14 Sep 2017 06:34:35 GMT
Server:squid/3.5.20
Keep-Alive:timeout=38
Vary:Accept-Encoding
...
<!DOCTYPE html>
<html>
<head>
在接受了所有数据之后,连接会被浏览器再次关闭,一次访问就算结束了。
closing connection #0
URL语法
所谓URL,就是我们平常所说的网址,它的全称叫做统一资源定位符(Uniform Resource Locators),虽然URL不是HTTP的一部分,但通常我们能够通过URL直观地进行HTTP和其他协议的通信。总体的URL例子可以表示为:
scheme://hostname:port/path?querystring#fragment
对应到NBA中文网的实例为:
http://nbachina.qq.com/a/20170914/004815.htm
scheme表示URL的模式,它定义了浏览器和服务器之间通信所采用的协议,NBA主页的例子里采用的模式就是http。紧随其后的是主机名hostname和端口号port,主机名提供了存放我们感兴趣资源的服务器的名字,它是一个服务器的唯一识别符。端口号一般默认为80,主机名和端口号组合起来就等于说是告诉浏览器要去敲哪一扇门才能访问请求的资源。主机名和端口号之后的路径用来确定被请求的资源在服务器上的位置,跟文件系统类似,也是用/符号来分段的。
另外,在多数情形下,URL的路径里会提供很多补充信息,用来帮助服务器正确的处理一些复杂的请求,比如说通过类似name=value这样的查询字符串来获取更多的信息,或者用#符号来指向网页中特定的部分也是常见的补充方法。
最后需要说明的是,URL是通过ASCⅡ字符集来实现编码的,所有不在128个字符集里面的字符和特殊字符串都需要转义编码为标准的表示法,URL编码也被成为百分号编码,这是因为每个这样的编码都是以%开头的。在R语言中,我们可以通过基础函数URLencode()和URLdecode()函数来对字符串进行编码或者解码:
char <- "Golden states Worriors is the NBA Champion in 2017"URLencode(char,reserve=TRUE)
[1] "Golden%20states%20Worriors%20is%20the%20NBA%20Champion%20in%202017"
URLdecode(char)
[1] "Golden states Worriors is the NBA Champion in 2017"
HTTP消息
HTTP消息无论是请求模式还是响应模式,都由起始行(start line)、标头(headers)(也叫消息报头)和正文(body)三部分组成。起始行是每个HTTP消息的第一行,它定义了请求使用的方法,以及所请求资源的路径和浏览器能够处理的HTTP最高版本。起始行之后的标头为浏览器和服务器提供了元信息,以“名字-取值”形式表示的一套标头字段。正文部分包含纯文本或者二进制数据,这由标头信息中的content-type声明决定。然后是MIME(多用途互联网邮件扩展)类型声明,这个声明的作用是告诉浏览器或服务器传输过来的是哪种类型的数据。起始行、标头和正文分开需要用到换行符(CRLF)。
在请求模式中,最常用的请求方法是GET和POST方法,在爬虫过程中至关重要。这两个方法都是从服务器请求一个资源,但是在正文的使用上有所不同,GET方法不会在请求的正文中发送任何内容,但POST会用正文来发送数据。
GET请求如下:
GET/form.html HTTP/1.1(CRLF)
在R中,RCurl包提供了一些高级函数来执行GET请求从Web服务器上获取某个资源,最常用的函数的getURL(),这个函数会自动确定主机、端口以及请求的资源。实际操作中,我们只需要把URL传给这个函数,也可以手动指定HTML表单参数:
library(RCurl)
getURL(http://nbachina.qq.com/a/20170914/004815.htm)
[1] "<!DOCTYPE html><html lang=\"zh-CN\"><head>\n<meta content=\"text/html;
charset=gb2312\" http-equiv=\"Content-Type\">\n<meta charset=\"gb2312\">
\n<title>1tμ<c7><b6><d4>±è<bb>e<bc>yó<eb>2012à×<f6>a£o<b6><bc>·<c7>
,... <truncated>
请求完后爬虫需求则依赖于后续的操作。
POST请求如下:
POST/greetings.html HTTP/1.1
在R中执行POST请求,无需手动构建,而是可以使用postForm()函数:
url<-“http://www.r-datacollection.com/materials/http/POSTexample.php”
cat(postForm(url,name=“Kobe”,age=39,style=“post”))
Hello Kobe!
You are 39 years old.
在将预先声明的参数填充到表单中去的时候,需注意利用style参数预先显式声明一下其可接受的方式。常见的HTTP请求方法如下:
方法 | 描述 |
GET | 从服务器检索资源 |
POST | 利用消息向服务器发送数据,然后从服务器检索资源 |
HEAD | 从服务器检索资源,但只响应起始行和标头 |
PUT | 将请求的正文保存在服务器上 |
DELETE | 从服务器删除一个资源 |
TRACE | 追踪消息到达服务器沿途的路径 |
OPTIONS | 返回支持的HTTP方法清单 |
CONNECT | 建立一个网络连接 |
浏览器发送请求后,服务器需要对其进行响应,会在响应的起始行发回一个状态码,可能大家会不太明白状态码是什么玩意儿,但louwill说一个404想必大家都知道了,404就是一个表示服务器无法找到资源的响应状态码。
而正常情形的响应状态码为200:
常见的HTTP状态码如下所示:
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
常见的200表示成功找到资源,404表示未找到资源,500表示服务器内部错误,502表示错误网关等。
有关爬虫基础部分的HTTP知识,louwill就给大家介绍到这里了,至于更深入的、更实际的一些情况,比如如何利用HTTP进行身份识别、认证和代理,libcurl库的详细介绍、RCurl的底层函数等其他内容将在R爬虫系列的后续内容中持续推出,也请各位期待~
参考资料:
Automated Data Collection with R
往期精彩:
【机器学习】决策树总结|ID3 C4.5/C5.0 CHAID CART与QUEST
Python高级特性:切片、迭代、列表生成式、生成器与迭代器
一个数据科学狂热者的学习历程