刚接触爬虫,由于本科主要是学java的,因此之前从java入手爬虫。其实就是模拟http请求,然后将返回的html代码提取自己想要的数据。不过说起来很简单,作为小白,实现起来还是不容易阿。
之前稍微看了下一个java的框架源代码(还没全部看完,不过和还是会抽时间看看的),不过导师让我用python实现,因而转入python(导师很喜欢python的样子阿)。
说起python的环境搭建等等,我作为刚入python的小白其实还不清楚,直接下载了一个python3的源码,然后,照着操作安装了下,其实很简单,不多说了。
爬网页第一步就是要获取html代码
说来python获取html十分简单,只要几行就可以了,把我给震惊到了!!像java还是要写不少行的,再加上异常,代码看着还是挺臃肿的(不过习惯了)。
#coding=utf-8
import urllib.request
def getHtml(url):
response= urllib.request.urlopen(url)
html = response.read()
return html
html = getHtml("http://www.baidu.com")
print(html)
这里爬取了百度首页的html代码,没错,这是这么简单。
这里用了一个urllib.request模块,其实我觉得把java代码封装下,写起来也没几行(纯属小白看法)。
试过了baidu之后想爬取下大众点评的首页,出现了403 forbid错误,一番查询后发现时缺少User-Agent,因此换一种方式,先创建一个request对象,然后将其加入头部即可:
request=urllib.request.Request(url)
request.add_header("User-Agent","xxx")
response=urllib.request.urlopen(request)
html=response.read()
print(html)
就是这么简单!
但还有编码的问题,返回的数据并没有解码,只要html.decode("utf-8")就可以了,具体的编码格式参照该网页的charset
不过也可以用chardet来检测该网页是什么编码,chardet模块需要下载,在命令行输入pip install chardet 即可。
import chardet
charset = chardet.detect(html)
if(charset['encoding'] != None):
html = html.decode(charset['encoding'])
return html
上述代码的html就是之前获取到的html,然后用chardet检测下,获取其中的encoding编码,用这个编码解码即可。
最后这个差点让我崩溃,哎,不得不吐糟,这个问题困扰了我整整一天,研究了很长时间,毕竟小白啊,很多东西还要学。这个问题就是用p3的这个获取html其实是字节而非字符串(这也是上面要用decode解码的原因),但是问题是这个字节可能是压缩过的。
这个问题是怎么来的呢,是在我爬取http://health.sina.com.cn/disease/department/knx/ 这个页面的时候出现的错误,返回的是这样一串东西b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xd5}iw\x1b\xc7\x95...... 然后我还异想天开的用上述方法解码,然后悲剧了UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte,我的天,然后我就一直在研究解码的问题了~~~~~,可是关键不在于解码啊,所以苦苦得不到结果。实在没办法,只能请大师兄帮我一起研究下什么个情况。
后来我们发现http://health.sina.com.cn/disease/department/kns/,爬取这个有时候能成功,有时候失败,这就很奇怪,这是什么个情况!!!!没办法,用Fiddler工具看下吧(正好之前下了这个抓包工具,很强大!!)然后来了一组同一网站有成功有失败的请求,仔细观察它们到底有啥差别,然后惊讶的发现,失败的那个响应头(应该是响应头里的吧)里多了个 Content-Encoding: gzip,尼玛!!!学linux,正好知道这个gzip,这不是压缩的一个命令么!!!难怪失败的response body应该要有3w多字节,实际只有1w多了。
既然已经有了方向,自然要看看到底是不是这个Content-Encoding: gzip在作怪了,这时候就要解压缩啊,百度后有了结果,由于这是字节的压缩,因此需要用到BytesIO和gzip,注意py3里BytesIO已经移到了io包里了(又百度半天)
from io import BytesIO
import gzip
#这里省略获取response的代码
if(response.headers.get('Content-Encoding')=='gzip'):
compresseddata = response.read()
# gzip解压缩
compressedstream = BytesIO(compresseddata)
gzipper = gzip.GzipFile(fileobj=compressedstream)
html = gzipper.read()
#解压缩完成
html = html.decode("UTF-8")#这里才是根据网页charset解码问题
print(html)
困扰了一天的问题总算解决了,哎,作为小白也是不容易啊!!还是要感谢下大师兄陪我一起折腾啊!!!希望能帮助到一些人,也以便我未来查阅。
来源:oschina
链接:https://my.oschina.net/u/2693668/blog/667252