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)})
    # 其余不变
    
  • 相关阅读:
    POJ 3140 Contestants Division (树dp)
    POJ 3107 Godfather (树重心)
    POJ 1655 Balancing Act (树的重心)
    HDU 3534 Tree (经典树形dp)
    HDU 1561 The more, The Better (树形dp)
    HDU 1011 Starship Troopers (树dp)
    Light oj 1085
    Light oj 1013
    Light oj 1134
    FZU 2224 An exciting GCD problem(GCD种类预处理+树状数组维护)同hdu5869
  • 原文地址:https://www.cnblogs.com/abyss1114/p/7898538.html
Copyright © 2011-2022 走看看