zoukankan      html  css  js  c++  java
  • Python:关于爬虫(1)

    要使用python编写爬虫代码,我们需要解决第一个问题是:

    Python如何访问互联网?

    回答这个问题不得不提到的就是urllib,它实际上是由两部分组成的:url+lib。

    url:就是我们平时所说的网页地址
    lib:library的意思

    URL的一般格式为(带方括号[]的为可选项):
    protocol://hostname[:port]/path/[;parameters][?query]#fragment

    URL由三部分组成:

    • 第一部分是协议:http,https,ftp,file,ed2k...

    http:Hypertext Transfer Protocol, 即超文本传输协议,万维网浏览服务程序所用的协议。

    https:Secure Hypertext Transfer Protocol,即安全超文本传输协议,在HTTP基础上增强的数据安全的部分。

    ftp:File Transfer Protocol , 即文件传送[输]协议。

    file:File协议主要用于访问本地计算机中的文件,就如同在Windows资源管理器中打开文件一样。基本的格式如下:file:///文件路径,比如要打开F盘flash文件夹中的1.swf文件,那么可以在资源管理器或[IE]地址栏中键入:file:///f:/flash/1.swf并回车。

    ed2k:eDonkey2000 network,是一种文件共享网络,最初用于共享音乐、电影和软件。与多数文件共享网络一样,它是分布式的;文件基于P2P原理存放于用户的电脑上而不是存储于一个中枢服务器。 说简单点就是emule下载地址的开头,也就是说要下载此种网址的文件必须用eMule,不过现在迅雷也支持[ed2k协议。

    • 第二部分是存放资源的服务器的域名系统或IP地址(有时候要包含端口号,各种传输协议都有默认的端口号,如http的默认端口号为80)。
    • 第三部分是资源的具体地址,如目录或文件名等。【第三部分通常是可以忽略的】

    在python2.x里面,含有urllib和urllib2两个模块(module),python3.x对它做了一个较大的改动,将其合并为一个包(package),统一称为urllib,它包含了四个模块(module):

    urllib.request—for opening and reading URLs
    urllib.error—containing the exceptions raised by urllib.request
    urllib.parse—for parsing URLs
    urllib.robotparser—for parsing robots.txt files

    举个例子:我们读取一个网页的内容

    import urllib.request
    response = urllib.request.urlopen("http://www.fishc.com")
    html=response.read()
    print(html)
    

    得到的结果是:

    网页内容

    进行解码:html=html.decode('utf-8')
    得到的结果是:

    网页内容


    实战

    推荐一个网站:placekitten.com

    A quick and simple service for getting pictures of kittens for use as placeholders in your designs or code. Just put your image size (width & height) after our URL and you'll get a placeholder.

    通过以下的方式就能得到你想要的尺寸的猫的图片:

    Like this: http://placekitten.com/200/300
    or:http://placekitten.com/g/200/300

    第一个例子:抓取图片

    我们新建一个downloadcat.py文件,执行下面这段代码:

    import urllib.request
    response = urllib.request.urlopen("http://placekitten.com/g/320/240")
    cat_img = response.read()
    with open("cat_320_240.jpg", "wb") as f:
        f.write(cat_img)
    

    在downloadcat.py的同级目录里面可以可以看到一个大小为320*240的图片:

    cat_320_240.jpg

    解读程序:urlopen()参数既可以是一个字符串,也可以一个request对象。实际上,response可以分解为:

    req=urllib.request.Request("http://placekitten.com/g/320/240")
    response=urllib.request.urlopen(req)

    urlopen实际上是返回一个对象,我们可以通过read()来读取它的内容。我们还可以:
    通过response.geturl()获取到图片的网址;
    通过response.info()来获得图片的详细信息;
    通过response.getcode()来获得状态码。

    print(response.geturl())
    print(response.info())
    print(response.getcode())
    
    第二个例子:利用有道词典翻译文本

    我们打开有道词典,输入英文之后,会自动翻译成中文

    有道翻译

    打开浏览器的审查元素,切换到Network,我们找到name目录下的translate_o开头的文件,点击打开之后可以看到它的Preveiws的信息:

    preview.png

    正是我们进行翻译的句子,接着切换到Headers,可以看到Headers的基本信息:

    headers.png

    其中:

    Remote Addresss是服务器的IP地址以及它打开的端口号
    Request URL是真正实现翻译的地址
    Request Method是请求的方式
    Status Code是状态码,200表示成功

    Request Headers是客户端发送请求的headers,它通常用于服务器端判断是否非人类访问,主要是通过User-Agent结构来识别是浏览器访问还是代码访问。它是可以简单自定义的。

    Form Data是post提交的主要内容。i后面是待翻译的文本内容

    在这个网址的笔记列表里面可以查看常见的状态码:
    http://www.runoob.com/ajax/ajax-xmlhttprequest-onreadystatechange.html
    我们新建一个py文件,执行下面的代码:

    import urllib.request as ur
    import urllib.parse
    # 获取Request URl
    request_url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&sessionFrom='
    # 获取到Form Data中的信息
    data = {
            'i': 'I love you',
            'from': 'AUTO',
            'to': 'AUTO',
            'smartresult': 'dict',
            'client': 'fanyideskweb',
            'salt': '1505653077725',
            'sign': '467d88b4cdc9c6adca72855020b6a1e8',
            'doctype': 'json',
            'version': '2.1',
            'keyfrom': 'fanyi.web',
            'action': 'FY_BY_CLICKBUTTION',
            'typoResult': 'true'
            }
    data=urllib.parse.urlencode(data).encode('utf-8')
    response = ur.urlopen(request_url, data)
    html=response.read().decode('utf-8')
    print(html)
    

    Take Note:
    记得去掉request_url中的"_0",否则会报错{"errorCode":50}

    得到的结果:

    运行结果.png

    从运行结果可知,得到的数据其实是json格式,它是一种轻量级的数据交换格式。关于json的用法,可以参考下面的网址:
    http://www.runoob.com/json/json-tutorial.html

    加入以下代码:

    import json
    target = json.loads(html)
    print(target)
    

    得到的结果是:

    json加载结果.png

    target的数据类型是dict,我们通过一层一层的访问方式:

    print(target['translateResult'])
    print(target['translateResult'][0][0])
    print(target['translateResult'][0][0]['tgt'])
    

    可以获得我们想要的目标信息:

    目标结果.png

    我们可以对代码进行简单修改,以此获得更好的用户体验:(省略部分与之前的一样)

    content = input("请输入需要翻译的内容:")
    ......
    'i':content
    ......
    print("翻译结果:%s" % target['translateResult'][0][0]['tgt'])
    

    测试结果:

    测试结果.png


    隐藏

    用以上的形式进行翻译会对服务器造成很大的负担,频繁访问肯能会被屏蔽。要想代码能够正常工作,我们需要对代码进行隐藏处理,让它的访问方式更贴近于浏览器的访问。

    根据上文介绍审查元素的一些特性时,我们提到了User-Agent的作用,现在我们就需要对它进行操作来模拟浏览器访问。
    我们在审查元素里面找到这个信息:

    User-Agent.png

    第一种修改方法:通过Request的headers参数修改,将response修改为两句,head的添加在req的前面进行。
    head = {}
    head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'
    ......
    req = ur.Request(request_url, data,head)
    response = ur.urlopen(req)
    ......
    
    第二种修改方法:通过Request.add_header()方法修改,将response修改为两句,head的添加在req的后面进行
    ......
    req = ur.Request(request_url, data)
    req.add_header('UserAgent','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36')
    response = ur.urlopen(req)
    ......
    

    检验方法:print(req.headers)

    检验结果.png

    Take Note:
    ur是简写,引入包的时候已经声明了
    import urllib.request as ur

    修改User-Agent是最简单的隐藏方法,但如果这是用于抓取网页的爬虫,那么一个IP地址短时间内会连续访问,这是不正常的,会对服务器产生较大的压力,返回给用户验证码的填写页面,爬虫是无法识别验证码的,这时候User-Agent就不起作用了。我们有两种方式可以处理这个问题。

    第一种:延迟提交的时间,让爬虫看起来比较正常

    我们可以将以上代码做如下处理:

    ......
    import time
    ......
    # 将主体代码进行缩进,放在一个while循环里面
    while True:
          content = input("请输入需要翻译的内容(输入'q!'退出程序):")
          if content == 'q!':
               break
          ......
          time.sleep(5000)
    

    第一次的翻译工作结束后五秒,才执行第二次翻译

    第一种方式弊端:效率低下。

    第二种:使用代理

    步骤:
    1.参数是一个字典{'类型':'代理ip:端口号'}
    proxy_support=urllib.request.ProxyHandler({})
    2.定制、创建一个opener
    opener=urllib.request.build_opener(proxy_support)
    3.1安装opener
    urllib.request.install_opener(opener)
    3.2调用opener[特殊需要的时候才使用可以不安装直接调用]
    opener.open(url)

    import urllib.request
    # 访问时会显示来源IP
    url = 'http://www.whatismyip.com.tw'
    # 按步骤,代理ip地址可以去网上找
    proxy_support = urllib.request.ProxyHandler({'http': '118.193.107.131:80'})
    opener = urllib.request.build_opener(proxy_support)
    urllib.request.install_opener(opener)
    response = urllib.request.urlopen(url)
    html = response.read().decode('utf-8')
    print(html)
    

    代理ip地址进行访问的时候可能会出现404等错误,可能是被过滤掉了,我们可以对代码简单修改,给opener加上headers信息

    opener.addheaders = [('UserAgent','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36')]
    

    为了避免ip不稳定而导致访问出错的问题,我们可以建立一个ip_list,随机使用其中一个ip进行访问

    ip_list = [ ]
    proxy_support = urllib.request.ProxyHandler({'http': random.choice(ip_list)})
    # 其余不变
    
  • 相关阅读:
    MySQL LIMIT OFFSET
    Sublime Text 3安装清爽主题(著名的Soda Theme)
    MySQL无法远程连接解决方案
    算法题:李嘉诚保险柜密码问题
    一些不错的算法学习练习站点
    [转]MySQL远程连接ERROR 2003 (HY000):Can't connect to MySQL server on'XXXXX'(111) 的问题
    使用什么工具连接MySQL Server
    CentOS 7修改MySQL 5.6字符集为UTF-8
    CentOS 7 Minimal编译安装MySQL5.6
    如何使浏览器默认下载文件而不是打开文件
  • 原文地址:https://www.cnblogs.com/abyss1114/p/7898538.html
Copyright © 2011-2022 走看看