Python——网络爬虫

此篇文章继续跟着小甲鱼的视频来初学网络爬虫,除了小甲鱼的网站上可下载视频,发现b站上也有全套的视频哦,会比下载来的更方便些。html

网络爬虫,又称为网页蜘蛛(WebSpider),很是形象的一个名字。若是你把整个互联网想象成相似于蜘蛛网同样的构造,那么咱们这只爬虫,就是要在上边爬来爬去,顺便得到咱们须要的资源。咱们之因此可以经过百度或谷歌这样的搜索引擎检索到你的网页,靠的就是他们大量的爬虫天天在互联网上爬来爬去,对网页中的每一个关键词进行索引,创建索引数据库。在通过复杂的算法进行排序后,这些结果将按照与搜索关键词的相关度高低,依次排列。算法

1 urllib模块

urllib模块其实是综合了url和lib的一个包。数据库

url的通常格式为:json

protocol://hostname[:port]/path/[;parameters][?query]#fragment

URL 由三部分组成:api

第一部分是协议:http,https,ftp,file,ed2k…浏览器

第二部分是存放资源的服务器的域名系统或IP地址(有时候要包含端口号,各类传输协议都有默认的端口,如http的默认端口是80)服务器

第三部分是资源的具体地址,如目录或者文件名等网络

举一个例子说明:app

import urllib.request response = urllib.request.urlopen("http://www.fishc.com") html = response.read() print(html) #二进制数据
 html = html.decode('utf-8') #对二进制数据解码
print(html)

当遇到不了解的模块时,可经过IDLE中Help中打开Python的文档进行搜索查看,也可使用print(模块名.__doc__)或者help(模块名)进行属性和使用方法的查看。以下为文档中urlopen的用法:框架

实例1:在placekitten网站下载一只猫的图片

import urllib.request response = urllib.request.urlopen("http://placekitten.com/g/300/300") #urlopen返回一个对象
cat_img = response.read()  #对象都可用print()打印出来 # response.geturl() 获得url #response.getcode() 返回值200,说明网站正常响应 response.info()获得文件信息
with open('cat_300_300.jpg','wb') as f: f.write(cat_img)

可看到在当前运行目录下已成功下载了图片。

urlopen的url参数既能够是字符串也能够是一个request对象,则咱们还能够将代码写成以下形式:

import urllib.request req = urllib.request.Request("http://placekitten.com/g/300/300") response = urllib.request.urlopen(req) cat_img = response.read() with open('cat_500_600.jpg','wb') as f: f.write(cat_img)

实例2:利用百度翻译进行翻译

小甲鱼的视频中的实例是有道翻译,运行结果以下:

看弹幕说是有道翻译加了反爬虫机制,因此本身用百度翻译作了一个,研究了好一下子,新手仍是懵懵懂懂的,不过作出来了仍是很开心的。代码以下所示:

import urllib.request import urllib.parse import json while True: content = input("请输入须要翻译的内容(退出q):") if content in['q','Q']: break
    else: url='http://fanyi.baidu.com/v2transapi' data={} data['from'] = 'en' data['to'] = 'zh' data['query'] = content data['transtype'] = 'translang' data['simple_means_flag'] = 3 data = urllib.parse.urlencode(data).encode('utf-8') response = urllib.request.urlopen(url,data) html = response.read().decode('utf-8') target = json.loads(html) print("翻译结果为:%s"%(target['trans_result']['data'][0]['dst']))

打开翻译首页,点击翻译,在Network中找打方法为post的项,各个浏览器可能有差别,可尝试在Network里的XHR中查找。

代码中的url和data是复值表头中的url和Form Data,在IE浏览器中我找了很久,下面分别为360浏览器和IE浏览器的截图:

360:

IE:

接着咱们解释此行代码:

data = urllib.parse.urlencode(data).encode('utf-8')

当data未赋值时,是以GET的方式提交,当data赋值后,POST将会取代GET将数据提交。如上图所示,data必须基于某一模式,咱们使用urllib.parse.urlencode()便可将字符串转换为须要的模式。

代码中使用了josen模块,由于直接打印出html出来的是json格式的数据不利于直接观看。最终运行结果以下所示:

2 隐藏

为何要进行隐藏操做?由于若是一个IP在必定时间访问过于频繁,那么就会被被访问网站进行反爬虫拦截,没法进行咱们爬虫的后续工做了,因此要给爬虫披上一层神秘的面纱,从而瞒天过海喽~

两种方法隐藏(修改)headers:

(1)经过Request的headers参数修改

(2)经过Request.add_header(key,val)方法修改

文档中说到headers必须是字典的形式,因此方法(1)直接经过增长字典键和对应值的方式来进行隐藏,以下所示,找到Request Headers中的User-Agent对应的值进行添加。

import urllib.request import urllib.parse import json while True: content = input("请输入须要翻译的内容(退出q):") if content in['q','Q']: break
    else: url='http://fanyi.baidu.com/v2transapi' head = {} head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36' data={} data['from'] = 'en' data['to'] = 'zh' data['query'] = content data['transtype'] = 'translang' data['simple_means_flag'] = 3 data = urllib.parse.urlencode(data).encode('utf-8') req = urllib.request.Request(url,data,head) response = urllib.request.urlopen(req) html = response.read().decode('utf-8') target = json.loads(html) print("翻译结果为:%s"%(target['trans_result']['data'][0]['dst'])) 

运行结果及headers是否正确输入的检查:

请输入须要翻译的内容(退出q):love 翻译结果为:爱 请输入须要翻译的内容(退出q):q >>> req.headers #检查
{'User-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}

第二种方法:

import urllib.request import urllib.parse import json while True: content = input("请输入须要翻译的内容(退出q):") if content in['q','Q']: break
    else: url='http://fanyi.baidu.com/v2transapi'

## head = {} ## head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
 data={} data['from'] = 'en' data['to'] = 'zh' data['query'] = content data['transtype'] = 'translang' data['simple_means_flag'] = 3 data = urllib.parse.urlencode(data).encode('utf-8') ## req = urllib.request.Request(url,data,head)#替换成下一句,由于再也不引用上面的head因此去掉head
        req = urllib.request.Request(url,data) #使用add_header(key,value)
        req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36') response = urllib.request.urlopen(req) html = response.read().decode('utf-8') target = json.loads(html) print("翻译结果为:%s"%(target['trans_result']['data'][0]['dst'])) 

第三种方法是引入休息时间,调用time模块的time.sleep来延长时间以免网站认为是爬虫非法访问。

第四种方法是引入代理,代理把看到的内容返回给你,因此能够达到一样的效果。使用代理的步骤以下:

1. 参数是一个字典 {‘类型’:‘代理ip:端口号’}

proxy_support = urllib.request.ProxyHandler({})

2. 定制、建立一个 opener

opener = urllib.request.build_opener(proxy_support)

3a. 安装 opener
urllib.request.install_opener(opener)

3b. 调用 opener

opener.open(url)

import urllib.request url='http://www.whatismyip.com.tw'
##iplist=['']
 proxy_support = urllib.request.ProxyHandler({'http':'115.46.123.180:8123'}) #proxy_support = urllib.request.ProxyHandler({'http':random.choice(iplist)})
 opener=urllib.request.build_opener(proxy_support) opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36')] urllib.request.install_opener(opener) response=urllib.request.urlopen(url) html=response.read().decode('utf-8') print(html)

运行结果以下所示,返回的IP地址是你的代理IP地址。

3 爬虫抓取煎蛋妹子图

跟着小甲鱼的视频去煎蛋网抓取妹子图啦,下述内容将自动进行和谐咔咔咔...

思路:新建本地保存图片文件夹→打开网站→记住图片的地址→保存图片到相应的文件夹

如图为煎蛋网妹子图网页显示,图片是按照页码来放置的。

咱们发现点击不一样的页码,url改变的只是页码处的数字。

http://jandan.net/ooxx/page-190#comments

首先咱们要获取页码,在页码处右键点击审查元素,以下所示:

则咱们能够读取到网页的html,而后使用find函数来找到[190]中的数字190,也就是当前页码。

接着咱们要获取当前页码下每张图片的url,一样在图片点击右键选择审查元素,可看到图片的地址以下:

嘻嘻,是gakki。以上是准备工做,接着咱们就能够写出大概的框架来,其他的内容由函数封装实现

def download_mm(folder = 'ooxx',pages = 10): os.mkdir(folder) os.chdir(folder) url='http://jandan.net/ooxx/' page_num = int(get_page(url)) for i in range(pages): page_num -= i page_url = url + 'page-' + str(page_num) + '#comments' img_addrs = find_imgs(page_url) save_imgs(folder,img_addrs)

完整实现代码以下所示:

import urllib.request import os def url_open(url): req = urllib.request.Request(url) req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36') response = urllib.request.urlopen(req) html = response.read() return html def get_page(url): html = url_open(url).decode('utf-8') a = html.find('current-comment-page') + 23 b = html.find(']',a) return html[a:b] def find_imgs(url): html = url_open(url).decode('utf-8') img_addrs = [] a = html.find('img src=') while a != -1: b = html.find('.jpg',a,a+255) if b != -1: img_addrs.append(html[a+9:b+4]) else: b = a + 9 a = html.find('img src=',b) return img_addrs def save_imgs(folder,img_addrs): for each in img_addrs: filename = each.split('/')[-1] with open(filename, 'wb') as f: img = url_open("http:"+each) f.write(img) def download_mm(folder = 'ooxx',pages = 10): os.mkdir(folder) os.chdir(folder) url='http://jandan.net/ooxx/' page_num = int(get_page(url)) for i in range(pages): page_num -= i page_url = url + 'page-' + str(page_num) + '#comments' img_addrs = find_imgs(page_url) save_imgs(folder,img_addrs) if __name__ =='__main__': download_mm() 

成功在本地新建的文件夹中获取到了jpg的图片。

4 异常处理

(1)URLError

当urlopen没法处理一个响应的时候,就会引起URLError异常。 一般,没有网络链接或者对方服务器压根儿不存在的状况下,就会引起这个异常。同时,这个URLError会伴随一个reason属性,用于包含一个由错误编码和错误信息组成的元组。

(2)HTTPError

HTTPError是URLError的子类,服务器上每个HTTP的响应都包含一个数字的“状态码”。有时候状态码会指出服务器没法完成的请求类型,通常状况下Python会帮你处理一部分这类响应(例如,响应的是一个“重定向”,要求客户端从别的地址来获取文档,那么urllib会自动为你处理这个响应。);可是呢,有一些没法处理的,就会抛出HTTPError异常。这些异常包括典型的:404(页面没法找到),403(请求禁止)和401(验证请求)。

下述举例说明Python处理异常的两种方法:

from urllib.request import Request,urlopen from urllib.error import URLError,HTTPError req = Request(someurl) try: response = urlopen(req) except HTTPError as e: print('The server coudln\'t fulfill the request.') print('Error code:',e.code) except URLError as e: print('We failed to reach a server.') print('Reason:',e.reason) else: #do something

 

注意HTTPError要在URLError前面。

from urllib.request import Request,urlopen from urllib.error import URLError,HTTPError req = Request(someurl) try: response = urlopen(req) except HTTPError as e: if hasattr(e,'reason') print('We failed to reach a server.') print('Reason:',e.reason) elif hasattr(e,'code'): print('The server coudln\'t fulfill the request.') print('Error code:',e.code) else: #do something
相关文章
相关标签/搜索