百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

数据大作战之网络爬虫

toyiye 2024-06-21 12:40 11 浏览 0 评论

连续一个星期了,一直是在抓数据。个人水平从小初班到了小中班。好歹是积累了些干货。感觉有必要总结总结了。

在上干货之前,我先说明下提纲。不感兴趣前部分就可以跳过了。

第一节,普及下网络数据请求过程

第二节,几种语言抓取数据的方式

第三节,Python抓取数据的方法和常见问题,包括中文乱码,post传值,域名登录,接口获取,数据解析处理等

一, 网络数据请求过程

我可以做一个这样的比喻,浏览网页就像是在跟另一个人用对讲机通话。是的。虽然我们一提到上网冲浪好像是在看电影似的,完全是坐享其成的感受。但是实际上这是一种错误的认识。上网就是在通话,用户在一头说话,服务器在另一头回应。如果用户没有任何操作,你想要的网页是不会跳出来的。而浏览器就相当于对讲机,展示数据的载体。http协议就相当于通话双方的频段。

再提到域名就不能用对讲机举例了,就要拿电话机来比喻了。我们所有访问的网站,都代表了一个完全独立唯一的个体,就像电话号码。但是电话号码太长了,就需要用另一种容易记忆的方式来标示,这就出现了各种www域名,就像我们手机通讯录存储的姓名。试想一下每次使用百度都输入’61.135.169.121’这样一串数字,谁能吃得消啊。实际上在咱们往浏览器输入简单的www.baidu.com的时候,浏览器仍然在需要在庞大的域名数据库里查询对应的ip地址才能访问到目标网站。比如说你想找北京水利局长,即使你很明确你要找的人是谁也无法和他通话,因为你首先要通过查询找到他的电话号码才能拨通。如果你找不到他的号码,就会得到提示‘查无此人’,这种事情发生在网络上就会出现最经典的404报错。

假设网站可以正常访问了,相当于电话拨通了。但是并不代表可以正常通话了。因为对方是水利局长每天受到的骚扰多了去了,首先你得表明身份是什么地方的谁谁谁,当电话那头允许了。你这边再说一句‘下面我将表明我的诉求‘,再接下来才是进入网络访问过程。这就是传说中的三次握手。

既然通话网路已经建立,就进入到了通话过程。一头说,“我想让某某给我唱一首伤心太平洋“”我想让某某某号给我讲一个笑话“,然后对讲机那一头就按你的要求进行回复。即使这个时候也是不能保证有求必应的,比如403错误,你想看看对方老婆照片,对方肯定是不允许的;再比如500错误,对方临时上厕所开小差抽风了没法正常通话了;还有一种属于正常300提示,对方转接到其它线路。

我所认识的网络请求就是这个样子了。希望能满足诸位某些疑惑,也欢迎提出在下认识中的不足之处。

二,几中编程语言抓取数据的方式

1)

本人是搞PHP的,其它领域就业余很多了。所以先拿php说吧,

最简单的就是fopen /file_get_contents函数了,这就特别像拿来主意了,相当于网页右键查看源代码再复制下来。但是实际上他的简单也说明了它的局限性,只能抓取现成的页面代码,对于post传值和需要登录的就无能为力了,而且它不能keeplive,就像每次通话都要重新拨号,得到需求后再挂断。有些影响效率,比较适用于文本内容比较简单而且不作处理的页面。

另一种就是curl模拟提交了,属于伪造浏览器访问。可以设置post参数,甚至可以传输文件,应该范围很广,尤其是公众号开发,第三方接口获取数据。缺点就是配置特别多,所以我猜大部分跟我一样使用复制大法进行套用。另外,curl对于登录验证码这种高难度的操作就不太灵了。

2)

再接下来说一说js,jquery,vue.js,jsonp,ajax,这几种不同的名字在获取数据方法其实都是一种方式,就是ajax异步获取。当然其中肯定是有差别的,后面再细说。

它的优点是不必整个页面重新获取,而是只获取某一个数字或图片或单独一页内容再进行填充,用户体验效果好,并且节省网络资源。缺点是它并非真正意义上的抓取数据,而是类似于接收数据。因为ajax获取的数据及数据格式都是预先定义好的,只需要按照预定参数去获取就好了。

其中jsonp是较特殊的一种了,优点是可以跨域,就是可以获取不同域名站点的内容。缺点是只能使用get提交。至于使用非jsonp跨域获取数据的ajax类似的在网上还有大把方法可寻。世上无难事,只怕有心人。

3)

Node.js,据说这是近两年特别火爆的语言。我就感觉做程序员就是个无底洞,三天两头出来个新语言,新升级,新类库。不学不行,学了也感觉就那样。所以我就看了两个小时的教程,get 了点皮毛,貌似是功能挺强大,操作也挺简单。可以完成各种高难度的数据抓取。下面是一段简单的抓取数据的源码,包含抓取到解析的过程,自行体会吧。

var http = require('http')

var cheerio = require('./cheerio')

var url = 'http://www.imooc.com/learn/348'

function filterChapter(html)

{

var $ = cheerio.load(html)

chapters = $('.chapter')

var courseData = []

chapters.each(function(item){

var chapter = $(this)

var chapterTitle = chapter.find('strong').text()

var videos = chapter.find('.video').children('li')

var chapterData = {

chapterTitle:chapterTitle,

videos:[]

}

videos.each(function(item){

var video = $(this).find('.J-media-item')

var videoTitle = video.text()

var id = video.attr('href').split('video/')[1]

chapterData.videos.push({

title:videoTitle,

id:id

})

})

courseData.push(chapterData)

})

return courseData

}

function printCourseInfo(courseData){

courseData.forEach(function(item){

var chapterTitle = item.chapterTitle

var chapterVideos = item.videos

console.log(chapterTitle+'\n')

chapterVideos.forEach(function(video){

var videoTitle = video.title

var videoId = video.id

console.log('['+videoId+']'+videoTitle)

})

})

}

http.get(url,function(res){

var html = ''

res.on('data',function(data){

html+=data

})

res.on('end',function(){

courseData = filterChapter(html)

//console.log(courseData)

printCourseInfo(courseData)

})

}).on('error',function(){

console.log('获取数据出错')

})

4)

最后再说一说python了,这门语言算是抓取数据的老牌专业户了,一提到它的名字就会联想到’爬虫’二字。我对它接触了有一个来月吧,就感觉python是个啥也不是,但是啥也能干的玩意。如果不加载模块好像啥也干不了了,但是所有想到的需求只要配合相关模块全都能做。比如能做网站,能做桌面应用程序,也能写用来执行爬虫的页面。

user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'

headers = { 'User-Agent' : user_agent }

response = urllib2.urlopen(request)

if response.getcode()!=200:

return None

return response.read()

这一段是基本的抓网页内容的代码,是不是比较牛逼,它的优点是完全伪装成浏览器的样子,连什么样的浏览器,什么样的系统,用什么方式去访问,需不需要ip代理,完全照办。所以我还是推荐使用python来抓取数据,代码简单,模块丰富,功能强悍,linux还自带python,只要花两三个小时就能get到一套受用的抓取方法。每次写好程序看着终端窗口不断跳动抓取过程,爽得不要不要的。

以上是我所知领域的抓取方式,毕竟也是小白一枚,未见过大世面。大牛大咖们莫要耻笑。

三,python爬虫的常见方法和问题总结

总算是进入干货阶段了,方法一说出来就很简单了。但是这些方法和问题却是实例开发中遇到且花长时间才找到解决方法的,比如说中文乱码的问题,我在网上查询解决方案,五花八门感觉都说得有理,折腾了三个多小时就是不成功。最终是自己尝试才找到方法,后面会详细说明。这里就不多说了。

首先说说爬取数据的方法,前面已经贴了一部分。在这里咱们再系统的罗列一遍。基本上用得都是urllib2和urllib模块。

a)最简单的不带参数的爬取。

f = urllib2.urlopen(url, timeout=5).read()

b)带header参数的

user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'

headers = { 'User-Agent' : user_agent }

request = urllib2.Request(url, headers = headers)

response = urllib2.urlopen(request)

if response.getcode()!=200:

return None

return response.read()

c)带post参数的

user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'

headers = { 'User-Agent' : user_agent }

value={

'name':'BUPT',

'age':'60',

'location':'Beijing'#字典中的内容随意,不影响#

}

postdata=urllib.urlencode(value)#对value进行编码,转换为标准编码#

request = urllib2.Request(url,data=postdata,headers = headers)

response = urllib2.urlopen(request)

if response.getcode()!=200:

return None

return response.read()

d)需要登录和验证码的页面,利用本地cookie文件爬取,需要使用cookielib模块

cookie=cookielib.MozillaCookieJar()

cookie.load('cookies.txt',ignore_expires=True,ignore_discard=True)

req=urllib2.Request('http://bbs.fobshanghai.com/qun.php?subcatid=576')

opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))

urllib2.install_opener(opener)

response=urllib2.urlopen(req)

print response.read()

PS:cookie文件可以利用firebug工具导出,要特别注意两点,1是在文本第一行加上‘# Netscape HTTP Cookie File’,这样一句话声明这是一个cookie文件,不然会报错,http.cookiejar.LoadError: 'cookies.txt' does not look like a Netscape format cookies file 2.检查一下每行的项目是不是齐全,里面包含了每条cookie的域名,布尔值,适用途径,是否使用安全协议,过期时间,名称,值共7个属性,缺一个就会报错。如果少的话,随便从其它行复制过来就可以。如果再报错,就用一个笨方法。复制一行正确的cookie,然后每个属性值一一复制粘贴过来。关键时刻还就得这样整。

e)获取json数据

按说获取接口的jsono数据是最简单的了,但是习惯使用beautiful模块去解析页面的DOM元素,遇到json数据反而傻眼了。所以在这里特别说明下json数据解析使用到的模块和方法。

解析json数据,我使用的是demjson模块,操作也是很简单的。使用datas = demjson.decode(soup),就可以像使用字典那样去取值了。

f)涉及用户登录及验证码的网页

针对验证码的爬取方法,网上同样有很多教程。但是本人没有成功完成的经验所以就不敢妄言了,目前来看掌握这几种方法就已经够用了。

说完了获取接下来就谈一谈解析了,毕竟拿到手的不是json数据而是一堆零乱的html文件,怎么取自己想的数据还要有很多路要走。我经常使用的beautiful模块,下面也是就这个模块来进行讲解。

a),获取id,class,以及标签的DOM元素

cont = soup.find('div',id="d_list") #获取id名称为‘d_list’的div元素

link.find('span',class_="c_tit") #获取class名称为’c_tit’的span元素,注意class_不同于’class’

b)获取元素的文本内容和属性值

soup.find('a').get_text() #获取a标签的文本内容

soup.find('a')['href'] #获取a标签的链接地址

soup.find('img')['src'] #获取图片地址

c)去除DOM元素中的部分元素

cont = soup.find('div',id="d_list")

cont.find('div',class_="ppp").extract() #去除id为’d_list’元素中的class为‘ppp’的div元素

d)去除a标签的href属性

del link.find('a')[‘href’] #实际开发中需要遍历操作

e)去除某DOM元素中的第N个某标签元素,或倒数第N个某标签元素

看似伤脑筋的题目,其实只要循环遍历其中所有元素,然后按照下标做选择判断就可以了。如果是去除倒数第N个元素,可以循环两次,第一次取到元素总数,第二次再相应操作就可以了。对于这种问题关键是思路。

f)图片地址问题

因为爬取数据的同时,也需要把图片抓取到本地,这就面临一个图片地址的问题。页面内容的图片地址和获取到自己服务器上的图片地址必须相对应。我在这里提供两个思路,一是如果抓取的网站里面的图片都是放在一个服务器上,那么就远程获取图片下载到自己服务器的相同目录下。这样图片抓到了,内容也抓到了,还不影响页面展示。所以把页面里的所有图片地址传到一个列表里,再一一远程下载到本地服务器。二是面对要抓取的网站里的图片来自不同服务器,这就有些棘手。即使是抓取到自己服务器相同的目录,也要使用正则表达把页面里图片的地址替换掉。我估计大部门程序员对正则还是有些怵的。所以我就采用了迂回战术,遍历出页面里所有的图片地址,分别下载到本地服务器后分别替换新地址。代码比较长就不在这里展示了,放个github库地址给大家观摩吧,https://github.com/zuoshoupai/code/tree/master/wxfunyparse。

常见的招数也就这些了,最后再说一说令人头疼的中文乱码问题。

网上对于乱码的说法有很多,大概也是由于造成乱码的原因有很多吧。不能全部适用。我就先把一般出现的原因罗列一下,a)页面本身是非utf8编码 ;b)程序开发环境也就是编辑器非utf8编码 c)服务响应的Accept-Encoding采用了gzip压缩 d)其它原因,比如cmd不支持显示中文或者设置不正确

因为造成乱码的原因有很多,所以我们首先要排查是哪种问题造成的。我的建议是在获取到页面的内容后马上输出,并导出到本地文件,也就是response.read()后马上打印。如果输出显示或是本地文件显示正常,就表示页面编码是没有问题的,问题出在解析上。所以使用response.read().encode('utf-8')解决问题。我上次遇到的问题很是奇葩,页面获取内容后打印输入正常,然后解析处理后就乱码了,我就使用各种decode,encode咋都不好使。最终没辙了,使用chardet模块把每一步的编码格式都打印出来,发现在传输过程中,gbk变成了utf8,也就是说明明是gbk的文本当成是utf8展示,而且还转不过来。最后我把最开始获取数据的地方转换成utf8就OK了。

希望这个小例子能给你带来一些启发,遇到bug千万不能乱,必须一步一步整理思路,确定问题所在,才能一击而中,成功解决。

好了,关于爬数据的知识总结就到这了。现在突然有种顿悟,所谓编程就是数据的交互,正确的传给别人和正确的拿到别人的。说来简单,中间的过程就是千辛万苦了。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码