浏览器抓取网页(用到一个神奇的库urllib.request.Request进行我们的模拟工作)

优采云 发布时间: 2021-12-02 06:22

  浏览器抓取网页(用到一个神奇的库urllib.request.Request进行我们的模拟工作)

  urllib.error.HTTPError:HTTP 错误 403:禁止

  从403 Forbidden我们可以发现,此时网站是禁止程序访问的。这是因为csdn网站 设置了反爬虫机制。当网站检测到爬虫时,访问会被拒绝,所以我们会得到上面的结果。

  这时候就需要模拟浏览器访问,以避免网站的反爬虫机制,然后顺利抓取到我们想要的内容。

  接下来,我们将使用魔法库 urllib.request.Request 进行我们的模拟工作。这次我们也会先上传代码,然后再解释,不过这次要提醒大家的是,下面的代码不能直接使用。my_headers 中的 User-Agent 替换为我自己的。因为为了保密我加了省略号,不能直接使用。更换方法如下图所示。这次为了使用方便,我们引入一个函数:

  #coding:utf - 8

from urllib.request import urlopen

from urllib.request import Request

import random

import re

def getContent(url,headers):

"""

此函数用于抓取返回403禁止访问的网页

"""

random_header = random.choice(headers)

"""

对于Request中的第二个参数headers,它是字典型参数,所以在传入时

也可以直接将个字典传入,字典中就是下面元组的键值对应

"""

req =Request(url)

req.add_header("User-Agent", random_header)

req.add_header("GET",url)

req.add_header("Host","blog.csdn.net")

req.add_header("Referer","http://www.csdn.net/")

content=urlopen(req).read().decode("utf-8")

return content

url="http://blog.csdn.net/beliefer/article/details/51251757"

#这里面的my_headers中的内容由于是个人主机的信息,所以我就用句号省略了一些,在使用时可以将自己主机的

my_headers = ["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/53 。。。Chrome/54.0.2840.99 Safari/537.36"]

print(getContent(url,my_headers))

  使用上面的代码,我们就可以正常的抓取到这个网页的信息了,接下来介绍如何获取我们的getContent函数中需要用到的headers中的参数。

  由于我们要模拟一个浏览器进行网页访问,这些参数自然需要我们在浏览器中搜索。

  首先我们点击进入要爬取的网页,然后右击页面,点击review元素,会出现如下图框,然后我们点击Network,然后我们会发现没有我们页面的信息都打开了,没关系,这时候我们刷新页面的时候,就会出现下图所示的信息。

  

  这时候我们会在第一行看到51251757,就是我们网页网址后面的标签。这时候我们点击这个标签,就会出现下图所示的内容:

  

  下面是我直接访问这个网址时得到的截图:

  

  前两张图,之前写过版本2的访问,现在直接用了。当时我在csdn主页上点了这个博客,所以在代码中的header里填了referer和前两张图。是的

  ,而且这张图是我直接通过URL链接进入浏览器访问的,所以从图中可以看出referer是,这是我们的网站,贴在这里是为了让大家更好的了解这个referer。不一样的画面。在这张图中,我用红线标出了需要填写的四个内容。测试的时候一定不要用我给的User-Agent,因为我用省略号代替了一些。每个人都需要用自己的方式来弥补。

  这时候我们就会发现Headers,是不是有一种豁然开朗的感觉?是的,你的直觉是对的,我们需要的信息在这个标题中。

  然后,根据代码中需要的参数,把信息复制回来就可以使用了,因为这里显示的信息正好对应了key值,所以我们复制使用起来非常方便。

  下面介绍一下这个urllib.request.Request的用法(从官方文档翻译过来的):

  类 urllib.request。request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None) 参数: url:不用说,这是我们即将访问的URL,是一个字符串。data:数据必须是一个字节对象,它指定要发送到服务器的附加数据,如果不需要,则为 None。目前,只有 HTTP 请求使用数据;当提供数据参数时,http 请求应该是 post 而不是 get。数据应以标准 application/x-www-form-urlencoded 格式进行缓冲。urllib.parse.urlencode() 函数的参数是一个映射或二进制序列,并以这种格式返回一个 ASCII 字符串。当它用作数据参数时,它应该被编码为字节。(我们暂时不需要这个,不用管它) headers: headers 是字典数据。当使用键和值参数调用 add_header() 时,此标头将作为请求进行处理。此标头通常用于防止爬虫访问服务器。头部是浏览器用来标识自己的,因为有些HTTP服务器只允许来自普通浏览器的请求而不是脚本(可以理解为爬虫)。

  这必然会增加网站服务器的处理负担,即网站必须在爬虫检测和网站服务器的计算负担之间进行权衡。所以爬虫检测机制不是越严格越好,必须考虑服务器的负担。origin_req_host: origin_req_host 应该是发出原创事务请求的主机,RFC 2965 定义了它。它默认为 http.cookiejar.request_host(self)。

  这是用户发起的原创请求的主机名或 IP 地址。例如,如果请求是针对 HTML 文档中的图像,则这应该是对收录图像的页面的请求的主机。(我们一般不使用这个,这里就知道了) unverifiable: unverifiable 应该表示请求是否是不可验证的,由RFC 2965定义,默认值为false。无法验证的请求意味着无法提交用户的 URL。例如,当用户在网页的html文档中找到一张图片,但用户没有权限从服务器上取回图片时,此时unverifiable值应该为true。method:method 应该是一个字符串,指示将使用 HTTP 请求方法(例如,“header”)。如果提供,它的值存储在方法属性中并由方法 get_method() 调用。子类可以通过在类中设置方法属性来指示默认方法。(这个我基本不会用。)说了这么多无聊的定义,我自己也受不了翻译了。让我们继续回到我们的程序:对于我们的程序,只需掌握几个要点。首先,我们必须构造一个请求:req =Request(url)。此时请求为空。我们需要向其中添加信息,供浏览器查看。只需掌握几个要点。首先,我们必须构造一个请求:req =Request(url)。此时请求为空。我们需要向其中添加信息,供浏览器查看。只需掌握几个要点。首先,我们必须构造一个请求:req =Request(url)。此时请求为空。我们需要向其中添加信息,供浏览器查看。

  req.add_header("User-Agent", random_header) 告诉网络服务器我是通过浏览器访问它,我不是爬虫。req.add_header("GET",url) 告诉浏览器我们正在访问的URL,req.add_header("Host","") 这是网站的信息,我们取自网站@ > 填写即可。这句话req.add_header("Referer","") 很重要。它告诉 网站 服务器我们在哪里找到了我们想要访问的网页。比如你点击了百度,如果一个链接跳转到当前访问的页面,那么referer就是百度中的链接,这是一个判断机制。对于 header 构造方法也可以这样做:

  #coding:utf - 8

from bs4 import BeautifulSoup

from urllib.request import urlopen

from urllib.request import Request

import random

import re

def getContent(url,headers):

"""

此函数用于抓取返回403禁止访问的网页

"""

random_header = random.choice(headers)

"""

对于Request中的第二个参数headers,它是字典型参数,所以在传入时

也可以直接将个字典传入,字典中就是下面元组的键值对应

"""

# req =Request(url)

# req.add_header("User-Agent", random_header)

# req.add_header("GET",url)

# req.add_header("Host","blog.csdn.net")

# req.add_header("Referer","http://www.csdn.net/")

header = {"User-Agent": random_header, "GET": url, "Host": "blog.csdn.net", "Referer": "http://www.csdn.net/"}

req=Request(url,None,header)

content=urlopen(req).read().decode("utf-8")

return content

url="http://blog.csdn.net/beliefer/article/details/51251757"

#这里面的my_headers中的内容由于是个人主机的信息,所以我就用句号省略了一些,在使用时可以将自己主机的User-Agent放进去

my_headers = ["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/53。。。(KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"]

print(getContent(url,my_headers))

  从上面的程序中可以看出,我们也可以直接构造header,但是这样做有一个缺陷,就是header中的User-Agent是硬编码的。其实我们可以发现,对于不同的主机访问同一个网页时,我们的另外三个信息:GET、Host、Referer可能都是一样的,而此时仅以User-Agent作为判断标准用户的异同,那么问题来了,如果我们向同学“借”一些User-Agents来使用,是不是模拟多个用户访问?是不是更酷。其实这就是我刚开始的代码中的原因,所以有一个my_headers的列表,里面其实可以放多个User-Agents,然后通过random函数随机选择一个组合起来创建一个用户。多人访问的错觉其实很有用。要知道,对于网站来说,访问过多会阻塞用户的ip。这不好玩,所以想要永久访问一个网站而不被屏蔽,还是需要很多技巧的。

  当我们要爬取一个网站的多个网页时,很容易被网站检测到,由于主机频繁访问,进而被拦截。而如果我们在列表中放更多不同的主机号并随机使用它们,是不是很容易被发现?当然,当我们防止这种情况时,更好的方法是使用IP代理,因为我们不容易获得很多主机信息,而IP代理很容易从互联网上搜索到。关于多次访问的问题我会在以后的博客中解释,这里就不多说了。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线