美文网首页
scrapy爬取整个网页时如何避免链接失效

scrapy爬取整个网页时如何避免链接失效

作者: 征途漫漫 | 来源:发表于2020-11-13 21:44 被阅读0次

    scrapy爬取整个网页时如何避免链接失效

    最近在使用scrapy爬取网页时遇到很多图片不能正常显示、a标签链接失效的情况,多是因为爬下来的网页和图片路径已经失去了原有的结构,网页无法根据标签的src或者标签的href找到对应的资源,下面就这个问题展开一个小研究。

    首先,做这个工作是一定要修改网页的,所以我们引入BeautifulSoup库对网页进行解析。

    其次,在本文中所有的网页以域名为目录名进行保存

    
    soup = bs(response.body, 'html.parser')
    
        for item in soup.find_all('a'):
    
            pass
    
    

    下面我们分情况讨论

    大体上看,网页中的链接有以下几种格式:

    第一种情况,链接直接以/开头,很明显是从网站的根目录开始检索,那么我们直接将该网站的存储路径加在page前即可(home_path代表当前网页在我们系统中保存的路径,包含域名):

    
    if item.get('href').startswith('/'):
    
        item['href'] = home_path + '/' + item.get('href')[1:]
    
    

    第二种情况,链接直接以http开头,结尾可能有'/'也可能没有,此时我们直接将其索引至域名目录下的index.html或index.jsp,具体看你要爬的网页的特征,此处只做示例,dir_website为我们保存爬取的网页的路径,不包含域名

    第三种情况,链接仍以http开头,结尾是资源的具体路径,这时候我们不仅要提取域名,还要提取出资源的位置。

    
    elif item.get('href').startswith('http'):
    
        if item.get('href').endswith('.com') or item.get('href').endswith('.com/'):
    
            item['href'] = os.path.join(dir_website, item['href'][item['href'].find('//')+2:item['href'].find('.com')+4], 'index.html')
    
        else:
    
            item['href'] = os.path.join(dir_website, item['href'][item['href'].find('//')+2:])
    
    

    注意,这个域名一定要从链接中提取,而不是直接插入当前爬取的网站域名,这是因为href里的链接不一定来源于当前网站,有可能索引到其他的网站,这时候如果我们同时爬取了它索引到的网站,通过这种方法我们仍然能够正常访问。

    第四种情况——'#content',href里的链接以'#'开头,代表你点击这个链接后在当前页面内查找id='content'的元素,并切换到该元素所在的位置。这种链接我们并不需要处理,直接continue即可。

    
    elif item.get('href').startswith('#'):
    
        continue
    
    

    第五种和第六种情况我们可以一起处理,这得益于python中path模块的一个方法:

    os.path.normpath()

    这个方法是什么意思呢,它可以把传入的url的格式调整为正确的格式,比如:

      print(os.path.normpath('/home/user//website/index.html'))
      #/home/user/website/index.html
      print(os.path.normpath('/home/user/./website/index.html'))
      #/home/user/website/index.html
      print(os.path.normpath('/home/user/../website/index.html'))
      #/home/website/index.html
    

    有了这个方法,我们可以直接转换第五种和第六种情况的链接。

    
    else:
    
        item['href'] = os.path.normpath(os.path.join(home_path, item['href']))
    
    

    至于第七种情况,很明显这种链接是通过向后端的Servlet发送请求来获取页面,而我们爬下来的网页是没有后端的,但是我们确实能够通过scrapy爬到这个网页,那我们就把爬下来的网页加上.html的后缀,然后给这个链接也加上后缀,我们就可以通过点击链接来访问目标资源了。

    当然,在那之前,我们得去掉网页链接里的'/',因为我们保存的网页文件名字里是不可能包含'/'的。

    
    if item.get('href').endswith('/'):
    
        item['href'] = item['href'][:-1]
    
    if not item.get('href').endswith('.html'):
    
        item['href'] = item.get('href') + '.html'
    
    

    至此,我们已经解决了大多数爬下来的网页资源不可达的问题了,以上是对于<a>标签做的处理,<img>标签同理,就不再赘述。

    还有一种比较少见的情况,就是网页内的资源url是经过编码的,比如'%'会变成'%25',此时我们只要将保存文件的名称进行解码后再保存即可,相关函数是urllib.unquote()。而网页内的链接无须解码,因为它们在访问资源时会自动解码。

    相关文章

      网友评论

          本文标题:scrapy爬取整个网页时如何避免链接失效

          本文链接:https://www.haomeiwen.com/subject/hiwbbktx.html