On a reptile of self-cultivation 3: Hidden exercises + review

## modified headers
        (there are some sites comparative hate crawlers, they do not like to be accessed by the program, they will check the source of the link, if the source is not the normal way, then it will take you to pinch back, so, we can let the program work continued to be put into production, we need to hide some of the code, making it look more like a normal ordinary people click on your browser. then we said before, the server checks by examining the link is a link in the Headers in the User Agent request to determine if you head from the code or from a browser, like our Python, you use the default Python Headers in the User Agent is Python plus the version number, check the server is a Python, we will put you Qiadiao Headers can modify to simulate normal browser access).
Here Insert Picture Description
        (resolved: urllib.request.Request this function takes a parameter headers, and he told us that by modifying the headers parameter, we can set up your own headers, this parameter must be a dictionary, you can go two ways to set The first one is you just set up a dictionary, and then passed as a parameter Request, or the second, after the Request is generated by calling add_head () he added, to spend a lesson examples to modify :)

        The first: a dictionary directly provided, as a parameter to Request and
Here Insert Picture Description
Here Insert Picture Description
        a second: after generating Request by calling add_head (), the first parameter is the key, the second parameter value is
Here Insert Picture Description
Here Insert Picture Description

##代理

        (修改 User-Agent 可以算是最简单的隐藏方法了,也是切实可行的,不过如果是用于抓取网页的爬虫,例如批量下载 图片,你一个 IP 地址短时间内连续的进行访问,那么这是不符合正常人类的标准的,正常人看看美眉几秒钟欣赏一个图,那很快了,那么你一个爬虫一秒钟要下载好几十,上百张图片,那么显然对服务器带来的压力不小,所以人家合情合理把你拒之门外,

        屏蔽的做法也很简单,只需要记录每个IP的访问频率,在单位时间内,如果访问频率超过一个阈值,那么就会认为这个IP很有可能是一个爬虫,那么服务器就会把不管它的User-Agent是什么东西了,服务器就直接返回一个验证码页面,因为用户会填写这个验证码,而这个爬虫没办法识别,那么就合理把他拒绝掉,

        就我们目前的学习水平来说,有两种策略可以对抗这种做法,第一种就是延迟提交的时间,让我们的爬虫看起来更像是一个正常的人类在浏览;还有一种就是使用代理)

        第一种:使用 time 模块来完成延迟操作

import urllib.request
import urllib.parse
import json
import time


while True:
    content = input("请输入需要翻译的内容(输入‘q!’退出程序):")
    if content == "q!":
        break


    # 从Request URL:拷贝过来。把_o删了
    url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule"
    '''
    head = {}
    #去浏览器上的有道翻译通过F12直接到Heades头那里去拷贝过来
    head["User-Agent"] ="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
    '''
    # data就是表单数据,把Form Data 中的内容拷贝过来
    data = {}
    data['i'] = content
    data['from'] = 'AUTO'
    data['to'] = 'AUTO'
    data['smartresult'] = 'dict'
    data['client'] = 'fanyideskweb'
    data['salt'] = '15803439446390'
    data['sign'] = '8e349204c5d1140741ffe43284595085'
    data['ts'] = '1580343944639'
    data['bv'] = 'bbb3ed55971873051bc2ff740579bb49'
    data['doctype'] = 'json'
    data['version'] = '2.1'
    data['keyfrom'] = 'fanyi.web'
    data['action'] = 'FY_BY_CLICKBUTTION'
    #使用urllib.parse.urlencode()函数将字符串转换为所需要的形式
    #把Unicode的文件格式转换为uf-8的编码形式
    data = urllib.parse.urlencode(data).encode('utf-8')

    req = urllib.request.Request(url, data)
    req.add_header("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36")

    response = urllib.request.urlopen(req)
    #解码的时候也要用uf-8来解码
    html = response.read().decode("utf-8")
    
    target = json.loads(html)
    target = target["translateResult"][0][0]["tgt"]
    
    print("翻译结果:%s"%(target))
    time.sleep(5)  #暂停5秒才可以继续翻译

Here Insert Picture Description
        (其实可以感受到,这样子工作效率很低)

        第二种:使用代理
        (就把需要访问的网址告诉代理先生,代理帮你访问,然后把他看到的所有内容原封不动的转发给你。这就是代理。工作原理就是这么简单,因此呢,服务器看到的IP地址就是代理的IP地址,而不是你的IP地址,这样子你用很多个代理同时发起访问,服务器也没有办法。使用代理的步骤如下:)

            ※步骤:
               1. 参数是一个字典 {‘类型’:‘代理ip:端口号’}
              proxy_support = urllib.request.ProxyHandler({})
        (它这个参数就是一个字典,字典的键就是代理的类型(如:http,https…),值就是对应的 ip 或者 域名 +端口号)

               2. 定制、创建一个 opener
              opener = urllib.request.build_opener(proxy_support)
        (opener可以看做是私人订制,当你使用 urlopen 打开一个普通网页的时候,你就是在使用默认的 opener 来工作,而这个opener 是可以有我们定制的,例如我们可以给它加上特殊的 headers,或者给他指定 代理,让他用这个代理IP去访问)

               3a. 安装 opener
              urllib.request.install_opener(opener)
        (我们使用 urllib.request.install_opener(opener),把它安装到系统中,这是一劳永逸的做法,因为在此之后,你只要使用普通的 urlopen() 函数,你就会自动地使用定制好的 opener 进行工作)

               3b. 调用 opener
              opener.open(url)
        (如果你不想替换掉默认的 opener,可以使用opener.open(url)语句调用 opener即使用你特殊的opener来打开网页。)

Here Insert Picture Description
        (我们需要代理ip,直接在网上搜索即可。)

import urllib.request
import random

url = 'http://ip.45fan.com/'

iplist = ['222.240.184.126:8086', '14.20.235.82:9797', '59.62.164.17:9999']

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 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36')]

urllib.request.install_opener(opener)

response = urllib.request.urlopen(url)
html = response.read().decode('utf-8')

print(html)

##温故知新之习题
            0. 服务器是如何识访问来自浏览器还是非浏览器的?
           答:通过发送的 HTTP 头中的 User-Agent 来进行识别浏览器与非浏览器,服务器还以 User-Agent 来区分各个浏览器。

            1. 明明代码跟视频中的栗子一样,一运行却出错了,但在不修改代码的情况下再次尝试运行却又变好了,这是为什么呢?
           答:在网络信息的传输中会出现偶然的“丢包”现象,有可能是你发送的请求服务器没收到,也有可能是服务器响应的信息不能完整送回来……尤其在网络阻塞的时候。所以,在设计一个“称职”的爬虫时,需要考虑到这偶尔的“丢包”现象。

            2. Request 是由客户端发出还是由服务端发出?
           答:我们之前说 HTTP 是基于“请求-响应”模式,Request 即请求的意思,而 Response 则是响应的意思。由客户端首先发出 Request,服务器收到后返回 Response。

           3. 请问如何为一个 Request 对象动态的添加 headers?
           答:add_header() 方法往 Request 对象添加 headers。

            4. 简单来说,代理服务器是如何工作的?他有时为何不工作了?
           答:将信息传给代理服务器,代理服务器替你向你要访问的服务器发送请求,然后在将服务器返回的内容返回给你。
           因为有“丢包”现象发生,所以多了一个中间人就意味着会多一层发生“丢包”的几率,且大多数代理并不只为一个人服务,尤其是免费代理。

           PS:大家想做“坏坏”的事情时可以考虑多几层代理,一般来说路由器日志并不会保存很长时间,几层代理后,基本很难查到是谁请求的。

            5. HTTP 有好几种方法(GET,POST,PUT,HEAD,DELETE,OPTIONS,CONNECT),请问你如何晓得 Python 是使用哪种方法访问服务器呢?
           答:使用 get_method() 方法获取 Request 对象具体使用哪种方法访问服务器。最常用的无非就是 GET 和 POST 了,当 Request 的 data 参数被赋值的时候,get_method() 返回 ‘POST’,否则一般情况下返回 ‘GET’。

            6. 上一节课后题中有涉及到登陆问题,辣么,你还记得服务器是通过什么来确定你是登陆还是没登陆的么?他会持续到什么时候呢?
           答:是 cookie,服务器通过判断你提交的 cookie 来确定访问是否来自”熟人“。
简单来说 cookie 可以分成两类:

           一类是即时过期的 cookies,称为“会话” cookies,当浏览器关闭时(这里是 python 的请求程序)自动清除
           另一类是有期限的 cookies,由浏览器进行存储,并在下一次请求该网站时自动附带(如果没过期或清理的话)

##动动手
           小甲鱼打算在这里先给大家介绍一个压箱底的模块 —— Beautiful Soup 4

           翻译过来名字有点诡异:漂亮的汤?美味的鸡汤?呃……

           好吧,只要你写出一个普罗大众都喜欢的模块,你管它叫“Beautiful Shit”大家也是能接受的……

           Beautiful Soup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。Beautiful Soup 会帮你节省数小时甚至数天的工作时间。

           这玩意儿到底怎么用?

           看这 -> 传送门

           上边链接是官方的快速入门教程(不用惧怕,这次有中文版了),请大家花差不多半个小时的时间自学一下,然后完成下边题目。

           噢,对了,大家可以使用 pip 安装(Python3.4 以上自带的神一般的软件包管理系统,有了它 Python 的模块安装、卸载全部一键搞定!)

           打开命令行窗口(CMD) -> 输入 pip install BeautifulSoup4 命令) -> 搞定。

            0. 编写一个爬虫,爬百度百科“网络爬虫”的词条
(链接 -> http://baike.baidu.com/view/284853.htm),将所有包含“view”的链接按下边格式打印出来:

Here Insert Picture Description
           提示:题目中需要使用到简单的正则表达式(在官方的快速入门教程有演示),如果你希望马上就深入学习正则表达式,当然可以给你预支一下后边的知识 ->Python3 如何优雅地使用正则表达式

           答:

import urllib.request
import re
from bs4 import BeautifulSoup

def main():
    url = "http://baike.baidu.com/view/284853.htm"
    response = urllib.request.urlopen(url)
    html = response.read()
    soup = BeautifulSoup(html, "html.parser") # 使用 Python 默认的解析器
    
    for each in soup.find_all(href=re.compile("view")):
        print(each.text, "->", ''.join(["http://baike.baidu.com", each["href"]]))
        # 上边用 join() 不用 + 直接拼接,是因为 join() 被证明执行效率要高很多
 
if __name__ == "__main__":
    main()

           1. 直接打印词条名和链接不算什么真本事儿,这题要求你的爬虫允许用户输入搜索的关键词。
然后爬虫进入每一个词条,然后检测该词条是否具有副标题(比如搜索“猪八戒”,副标题就是“(中国神话小说《西游记》的角色)”),如果有,请将副标题一并打印出来:

Here Insert Picture Description
           程序实现效果如下:
Here Insert Picture Description
           答:

import urllib.request
import urllib.parse
import re 
from bs4 import BeautifulSoup
 
def main():
    keyword = input("请输入关键词:")
    keyword = urllib.parse.urlencode({"word":keyword})
    response = urllib.request.urlopen("http://baike.baidu.com/search/word?%s" % keyword)
    html = response.read()
    soup = BeautifulSoup(html, "html.parser")
 
    for each in soup.find_all(href=re.compile("view")):
        content = ''.join([each.text])
        url2 = ''.join(["http://baike.baidu.com", each["href"]])
        response2 = urllib.request.urlopen(url2)
        html2 = response2.read()
        soup2 = BeautifulSoup(html2, "html.parser")
        if soup2.h2:
            content = ''.join([content, soup2.h2.text])
        content = ''.join([content, " -> ", url2])
        print(content)
 
if __name__ == "__main__":
    main()

            2. 哗啦啦地丢一堆链接给用户可不是什么好的体验,我们应该先打印 10 个链接,然后问下用户“您还往下看吗?

            来,我给大家演示下:
Here Insert Picture Description
            然后为了增加用户体验,代码需要捕获未收录的词条,并提示:
Here Insert Picture Description
提示:希望你还记得有生成器这么个东东
           答:

import urllib.request
import urllib.parse
import re 
from bs4 import BeautifulSoup
 
def test_url(soup):
    result = soup.find(text=re.compile("百度百科尚未收录词条"))
    if result:
        print(result[0:-1]) # 百度这个碧池在最后加了个“符号,给它去掉
        return False
    else:
        return True
 
def summary(soup):
    word = soup.h1.text
    # 如果存在副标题,一起打印
    if soup.h2:
        word += soup.h2.text
    # 打印标题
    print(word)
    # 打印简介
    if soup.find(class_="lemma-summary"):
        print(soup.find(class_="lemma-summary").text)   
 
def get_urls(soup):
    for each in soup.find_all(href=re.compile("view")):
        content = ''.join([each.text])
        url2 = ''.join(["http://baike.baidu.com", each["href"]])
        response2 = urllib.request.urlopen(url2)
        html2 = response2.read()
        soup2 = BeautifulSoup(html2, "html.parser")
        if soup2.h2:
            content = ''.join([content, soup2.h2.text])
        content = ''.join([content, " -> ", url2])
        yield content
        
 
def main():
    word = input("请输入关键词:")
    keyword = urllib.parse.urlencode({"word":word})
    response = urllib.request.urlopen("http://baike.baidu.com/search/word?%s" % keyword)
    html = response.read()
    soup = BeautifulSoup(html, "html.parser")
 
    if test_url(soup):
        summary(soup)
        
        print("下边打印相关链接:")
        each = get_urls(soup)
        while True:
            try:
                for i in range(10):
                    print(next(each))
            except StopIteration:
                break
            
            command = input("输入任意字符将继续打印,q退出程序:")
            if command == 'q':
                break
            else:
                continue
    
if __name__ == "__main__":
    main()

Published 247 original articles · won praise 116 · views 280 000 +

Guess you like

Origin blog.csdn.net/w15977858408/article/details/104114526