目前,我们的爬虫会跟踪所有之前没有访问过的链接。但是,一些网站会动态生成页面内容,这样就会出现无限多的网页。比如,网站有一个在线日历功能,提供了可以访问下个月和下一年的链接,那么下个月的页面中同样会包含访问再下个月的链接,这样页面就会无止境地链接下去,这种情况被称为爬虫陷阱。

想要避免陷入爬虫陷阱,一个简单的方法是记录到达当前网页经过了多少个链接,也就是深度。当到达最大深度时, 爬虫就不再向队列中添加该网页中的链接了。要实现这一功能, 我们需要修改seen变量。该变量原先只记录访问过的网页链接,现在修改为一个字典,增加了页面深度的记录。

#为避免爬虫陷阱,将用于避免重复链接的seen记录值修改为字典,增加记录访问次数
#现在有了这一功能,我们就有信心爬虫最终一定能够完成。
#如果想要禁用该功能,只需将max_depth设为一个负数即可,此时当前深度永远不会与之相等。
def link_crawler(..., max_depth=2):max_depth = 2seen = {}...depth = seen[url]if depth != max_depth:for link in links:if link not in seen:seen[link] = depth + 1crawl_queue.append(link)

将上述功能集成到之前的链接爬虫里,有以下代码:

import urllib.request
import urllib.error
import re #正则表达式
import urllib.parse #将url链接从相对路径(浏览器可懂但python不懂)转为绝对路径(python也懂了)
import urllib.robotparser #爬取数据前解析网站robots.txt文件,避免爬取网站所禁止或限制的
import datetime  #下载限速功能所需模块
def download(url, user_agent = "brain", proxy = None, num_retries = 2):  #下载url网页,proxy是支持代理功能,初始值为None,想要设置就直接传参数即可print("downloading:",url)header = {"user-agent": user_agent} #设置用户代理,而不使用python默认的用户代理Python-urllib/3.6req = urllib.request.Request(url, headers = header)    opener = urllib.request.build_opener()  #为支持代理功能时刻准备着if proxy:   #如果设置了proxy,那么就进行以下设置以实现支持代理功能proxy_params = { urllib.parse.urlparse(url).scheme: proxy }opener.add_handler(urllib.request.ProxyHandler(proxy_params))response = opener.open(req)try:html = urllib.request.urlopen(req).read()except urllib.error.URLError as e:    #下载过程中出现问题print("download error:",e.reason)html = Noneif num_retries > 0:     #错误4XX发生在请求存在问题,而5XX错误则发生在服务端存在问题,所以在发生5XX错误时重试下载if hasattr(e, "code") and 500<= e.code <600:return  download(url, user_agent, num_retries-1)  # recursively retry 5XX HTTP errorsreturn html
#download("http://example.webscraping.com") #访问正常
#download("http://httpstat.us/500") #这个网页测试用,一直是5XXerror#跟踪链接的爬虫
#link_crawler()函数传入两个参数:要爬取的网站URL、用于跟踪链接的正则表达式。
def link_crawler(seed_url, link_regex, max_depth=2):"""先下载 seed_url 网页的源代码,然后提取出里面所有的链接URL,接着对所有匹配到的链接URL与link_regex 进行匹配,
如果链接URL里面有link_regex内容,就将这个链接URL放入到队列中,
下一次 执行 while crawl_queue: 就对这个链接URL 进行同样的操作。
反反复复,直到 crawl_queue 队列为空,才退出函数。"""crawl_queue = [seed_url]max_depth = 2 #为避免爬虫陷阱,将用于避免重复链接的seen记录值修改为字典,增加记录访问次数;如果想要禁用该功能,只需将max_depth设为一个负数即可,此时当前深度永远不会与之相等seen = {seed_url:0} #初始化seed_url访问深度为0#seen = set(crawl_queue) #有可能链接中互相重复指向,为避免爬取相同的链接,所以我们需要记录哪些链接已经被爬取过(放在集合seen中),若已被爬取过,不再爬取while crawl_queue:url = crawl_queue.pop()rp = urllib.robotparser.RobotFileParser()   #爬取前解析网站robots.txt,检查是否可以爬取网站,避免爬取网站禁止或限制的rp.set_url("http://example.webscraping.com/robots.txt")rp.read()user_agent = "brain"if rp.can_fetch(user_agent, url):  #解析后发现如果可以正常爬取网站,则继续执行#爬取网站的下载限速功能的类的调用,每次在download下载前使用throttle = Throttle(delay=5) #这里实例网站robots.txt中的delay值为5throttle.wait(url)html = download(url)   #html = download(url, hearders, proxy=proxy, num_retries=num_retries)这里可以传所需要的参数html = str(html)#filter for links matching our regular expressionif html == None:continuedepth = seen[url]  #用于避免爬虫陷阱的记录爬取深度的depthif depth != max_depth:for link in get_links(html):if re.match(link_regex, link):link = urllib.parse.urljoin(seed_url, link) #把提取的相对url路径link(view/178)转化成绝对路径(/view/Poland-178)linkif link not in seen:  #判断是否之前已经爬取seen[link] = depth + 1 #在之前的爬取深度上加1crawl_queue.append(link) #之前没有的话这个链接可用,放在列表中继续进行爬取else:print("Blocked by %s robots,txt" % url)continuedef get_links(html):"""用来获取一个html网页中所有的链接URL"""#做了一个匹配模板 webpage_regex,匹配 <a href="xxx"> or <a href='xxx'>这样的字符串,并提取出里面xxx的URL,请注意这里的xxxURL很可能是源码中相对路径,eg view/1 正常访问肯定是打不开的webpage_regex = re.compile('<a href=["\'](.*?)["\']', re.IGNORECASE)return re.findall(webpage_regex,html)#return re.findall('<a[^>]+href=["\'](.*?)["\']', html)也可以这样实现,但没有上面的先编译模板再匹配好class Throttle:  #爬取网站的下载限速功能的类的实现,每次在download下载前使用"""Add a delay between downloads to the same domain"""def __init__(self, delay):self.delay = delay  # value of delay between downloads for each domainself.domains = {}   # timestamp of when a domain was last accessed记录上次访问的时间,小知识timestamp:时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。def wait(self, url):domain = urllib.parse.urlparse(url).netloclast_accessed = self.domains.get(domain)if self.delay>0 and last_accessed is not None:sleep_secs = self.delay - (datetime.datetime.now() - last_accessed).secondsif sleep_secs > 0:time.sleep(sleep_secs)  #domain has been accessed recently,so need to sleepself.domains[domain] = datetime.datetime.now()#只想找http://example.webscraping.com/index... or http://example.webscraping.com/view...
link_crawler("http://example.webscraping.com", "/(index|view)")

爬取网站前4_避免爬虫陷阱相关推荐

  1. python爬取网店数据_Python爬虫实现抓取京东店铺信息及下载图片功能示例

    本文实例讲述了Python爬虫实现抓取京东店铺信息及下载图片功能.分享给大家供大家参考,具体如下: 这个是抓取信息的 from bs4 import BeautifulSoup import requ ...

  2. python爬音乐评论生成词云图_python爬虫+词云图,爬取网易云音乐评论

    又到了清明时节,用python爬取了网易云音乐<清明雨上>的评论,统计词频和绘制词云图,记录过程中遇到一些问题 爬取网易云音乐的评论 一开始是按照常规思路,分析网页ajax的传参情况.看到 ...

  3. python网易云_用python爬虫爬取网易云音乐

    标签: 使用python爬虫爬取网易云音乐 需要使用的模块 只需要requests模块和os模块即可 开始工作 先去网易云音乐网页版找一下你想要听的歌曲点击进去.按键盘F12打开网页调试工具,点击Ne ...

  4. python爬虫爬取音乐_利用python爬虫实现爬取网易云音乐热歌榜

    利用python爬虫实现爬取网易云音乐热歌榜 发布时间:2020-11-09 16:12:28 来源:亿速云 阅读:102 作者:Leah 本篇文章给大家分享的是有关利用python爬虫实现爬取网易云 ...

  5. Python爬虫—爬取网易云音乐【热歌榜】歌曲的精彩评论(写入txt文本文件或者MySQL数据库)

      最近在学Python爬虫,看了Blibili爬取网易云音乐评论的视频,视频中是将一首歌的评论存入json文件,我在此代码的基础上扩展了三点:     1.爬取热歌榜200首歌曲的精彩评论:     ...

  6. python爬虫音乐图片的感受_python爬虫+词云图,爬取网易云音乐评论

    又到了清明时节,用python爬取了网易云音乐<清明雨上>的评论,统计词频和绘制词云图,记录过程中遇到一些问题 爬取网易云音乐的评论 一开始是按照常规思路,分析网页ajax的传参情况.看到 ...

  7. python爬虫爬取网易云音乐歌曲_Python网易云音乐爬虫进阶篇

    image.png 年前写过一篇爬网易云音乐评论的文章,爬不了多久又回被封,所以爬下来那么点根本做不了什么分析,后面就再改了下,加入了多线程,一次性爬一个歌手最热门50首歌曲的评论,算是进阶版了- 思 ...

  8. Python爬虫——selenium爬取网易云评论并做词云

    大家好!我是霖hero 到点了上号网易云,很多人喜欢到夜深人静的时候,在网易云听音乐发表评论,正所谓:自古评论出人才,千古绝句随口来,奈何本人没文化,一句卧槽行天下!评论区集结各路大神,今天我们来爬取 ...

  9. 如何用Python网络爬虫爬取网易云音乐歌曲

    今天小编带大家一起来利用Python爬取网易云音乐,分分钟将网站上的音乐down到本地. 跟着小编运行过代码的筒子们将网易云歌词抓取下来已经不再话下了,在抓取歌词的时候在函数中传入了歌手ID和歌曲名两 ...

最新文章

  1. 观百工堰竹筏竞技比赛有感
  2. 如何将通达信的预警股票发送到微信
  3. C++ Primer 5th笔记(3)字符串、向量和数组:字符串
  4. js样式会覆盖html样式,js实现html节点、CSS样式、事件的动态添加以及html覆盖层的添加...
  5. Controller数据导出Excel 详细教程——easypoi-base,easypoi-web,easypoi-annotation
  6. pygame精灵组有哪些方法_利用 pygame 开发一款游戏:「跳跳兔」(六)
  7. 开课吧Java:微服务设计遵循的规约有哪些?
  8. tensorflow中的py_function与watch
  9. 全网首发:OPPO推送:服务器端的参考代码,JAVA版
  10. lpt监控安装_lpt1(如何在lpt1端口安装打印机)
  11. SOUI中几个view视图控件的基本使用
  12. 反垃圾邮件智能网关之梭子鱼
  13. exchange 服务器设置自动答复,Exchange自动回复设置配置
  14. Codeforces Global Round 16 D2. Seating Arrangements (hard version)
  15. 常用的common function库(三)
  16. php微信小程序毕业设计 php化妆品商城小程序毕业设计毕设作品参考
  17. springcloud24:分布式事务 Seata处理分布式事务总结篇
  18. Live800:在线客服系统排名是怎么样的?
  19. Cycle3-Group1
  20. 第3天-Jenkins详解

热门文章

  1. Python之美[从菜鸟到高手]--urllib源码分析
  2. 美国银行Capital One承认被黑客攻击,超1亿个人数据遭窃
  3. 如何在Windows自带的邮件中关联自己的163网易邮箱
  4. oracle 查询近七天的数据
  5. ROS-Industrial工业机器人培训课程资料-2019更新-Melodic、Kinetic、Indigo
  6. 基本模型机的设计与实现
  7. GIScloud,一个基于网络的地理信息系统云计算方案 (专题一)
  8. 集合框架之List、Array List、set、Map
  9. 黑武器linux下载地址,酷毙了!暗黑版 Arch,BlackArch Linux 2017.03.01发布
  10. java 输入五种水果_java代码,实现输入编号,输出对应水果的单价~~~~