zoukankan      html  css  js  c++  java
  • 学习爬取

     最简单的单页面抓取 
    思路: 
    获取页面所有url 
    对获取的所有url进行分类 
    A 获取属于本域名下的url 
    B 获取属于其他url

    2 用到的模块 
    urllib 
    详细介绍见链接 
    http://blog.csdn.net/dolphin_h/article/details/45296353

    bs4 
    详细介绍见链接 
    http://blog.csdn.net/winterto1990/article/details/47624167

    re正则表达式 
    详细介绍见链接 
    http://blog.csdn.net/winterto1990/article/details/47624167

    3 一下代码出自freebuf文章,链接 
    http://www.freebuf.com/news/topnews/96821.html

    代码说明:

    import urllib
    from bs4 import BeautifulSoup
    import re
    
    def get_all_url(url):
       urls = []
       web = urllib.urlopen(url)#使用urllib模块的urlopen函数打开url,复制给web
    soup =BeautifulSoup(web.read())#将web内容转化为beautigulsoup格式的数据。
    
    #通过正则过滤合理的url(针对与freebuf.com来讲)
       tags_a =soup.findAll(name='a',attrs={'href':re.compile("^https?://")})
       #soup.findall函数的运用,配合正则表达式来过滤url
        try :
           for tag_a in tags_a:
    #re:^ 表示匹配字符串开头例如,^ abc 匹配 abc
        ? 表示匹配前一个字符串0次或1次,例如 abc? 匹配 ab 和 abc
           #return urls
       except:
           pass
       return  urls
    
    
    #得到所有freebuf.com下的url
    def get_local_urls(url):
       local_urls = []
       urls = get_all_url(url)
       for _url in urls:
           ret = _url
           if 'freebuf.com' in ret.replace('//','').split('/')[0]:
               local_urls.append(_url)
       return  local_urls
     #if 'freebuf.com' in ret.replace('//','').split('/')[0]:这个if语句不是很明白,通过split()函数,把域名分割,获取分割后组成的类表的第一个字符串。但是在分割前为什么要把//替换成空格???
    
    
    #得到所有的不是freebuf.com域名的url
    def get_remote_urls(url):
       remote_urls = []
       urls = get_all_url(url)
       for _url in urls:
           ret = _url
           if "freebuf.com" not in ret.replace('//','').split('/')[0]:
               remote_urls.append(_url)
       return  remote_urls
    
    
     #主函数
    def __main__():
       url = 'http://freebuf.com/'
       rurls = get_remote_urls(url)
       print "--------------------remote urls-----------------------"
       for ret in rurls:
           print ret
       print "---------------------localurls-----------------------"   
       lurls = get_local_urls(url)
       for ret in lurls:
           print ret
    
    
    if __name__ == '__main__':
    __main__()
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    上面是单独对一个页面抓取。如果对整个站点抓取的话,还设计到url的处理,用作者的原话: 
    我们可以把整站当成一个错综复杂的图结构,有一些算法基础的读者都会知道图的简单遍历方法:dfs和bfs(深度优先和广度优先)。如果这里读者有问题的话建议先去学习一下这两种算法。大体的算法结构我们清楚了,但是在实现中我们显然需要特殊处理url,需要可以区分当前目标站点域名下的网站和其他域名的网站,除此之外,在href的值中经常会出现相对url,这里也要特别处理。 
    下面是代码:

    import urllib
    from bs4 import BeautifulSoup
    import urlparse
    import time
    import urllib2
     #urllib 和 urllib2的区别http://blog.csdn.net/dolphin_h/article/details/45296353
    
    url = "http://xxxx.xx/"
    domain = "xxxx.xx"
    deep = 0
    tmp = ""
    sites = set()
    visited = set()
    #local = set()
    #集合:
    python的set和其他语言类似, 是一个无序不重复元素集, 基本功能包括关系测试和消除重复元素. 集合对象还支持union(联合), intersection(交), difference(差)和sysmmetric difference(对称差集)等数学运算.  
    
    def get_local_pages(url,domain):
       global deep
       global sites
       global tmp
       repeat_time = 0
       pages = set()
    
    
        #防止url读取卡住
       while True:
           try:
               print "Ready to Open the web!"
               time.sleep(1)
               #time.sleep()函数,
               Python time sleep() 函数推迟调用线程的运行,可通过参数secs指秒数,表示进程挂起的时间
    
               print "Opening the web", url
               web = urllib2.urlopen(url=url,timeout=3)
               print "Success to Open the web"
               break
           except:
               print "Open Url Failed !!! Repeat"
               time.sleep(1)
               repeat_time = repeat_time+1
               if repeat_time == 5:
                    return
       #上面整段判断url能不能打开
    
    
       print "Readint the web ..."
       soup = BeautifulSoup(web.read())
       print "..."
    #提取标签 a
       for tag in tags:
    
           #避免参数传递异常
           try:
               ret = tag['href']
           except:
               print "Maybe not the attr : href"
               continue
           o = urlparse.urlparse(ret)
           #urlparse.urlparse函数的使用
           urlparse模块主要是把url拆分为6部分,并返回元组。并且可以把拆分后的部分再组成一个url。主要有函数有urljoin、urlsplit、urlunsplit、urlparse等。 
    
    urlparse.urlparse(urlstring[, scheme[, allow_fragments]])
    
        将urlstring解析成6个部分,它从urlstring中取得URL,并返回元组 (scheme, netloc, path, parameters, query, fragment),但是实际上是基于namedtuple,是tuple的子类。它支持通过名字属性或者索引访问的部分URL,每个组件是一串字符,也有可能是空的。组件不能被解析为更小的部分,%后面的也不会被解析,分割符号并不是解析结果的一部分,除非用斜线转义,注意,返回的这个元组非常有用,例如可以用来确定网络协议(HTTP、FTP等等 )、服务器地址、文件路径,等等。
           """
           #Debug I/O
           for _ret in o:
               if _ret == "":
                    pass
               else:
                    print _ret
           """
    
    
    
           #处理相对路径url
           if o[0] is "" and o[1] is "":
               print "Fix  Page: " +ret
               url_obj = urlparse.urlparse(web.geturl())
               #获取web页面的url,用urlparse函数抽离
               ret = url_obj[0] + "://" + url_obj[1] + url_obj[2] + ret
               #组成一个绝对url
               #保持url的干净
               ret = ret[:8] + ret[8:].replace('//','/')
               o = urlparse.urlparse(ret)
    
                         #这里不是太完善,但是可以应付一般情况
    
               if '../' in o[2]:
                    paths = o[2].split('/')
                   for i inrange(len(paths)):
                        if paths[i] == '..':
                            paths[i] = ''
                            if paths[i-1]:
                                paths[i-1] = ''
                    tmp_path = ''
                    for path in paths:
                        if path == '':
                            continue
                        tmp_path = tmp_path + '/' +path
                    ret =ret.replace(o[2],ret_path)
               print "FixedPage: " + ret
    
    
          上面整段都是判断获到的url是绝对url还是相对url。如果是相对url,则还需进行重组成完善的绝对url。包括url中含../的情况进行处理。但是处理../的情况不理解!!???
    
           #协议处理
           if 'http' not in o[0]:
               print "Bad  Page:" + ret.encode('ascii')
               continue
    
           #url合理性检验
           if o[0] is "" and o[1] is not "":
               print "Bad  Page: " +ret
               continue
    
           #域名检验
           if domain not in o[1]:
           #变量domain用来检验获取的所有url是否是改域名下的
               print "Bad  Page: " +ret
               continue
    
           #整理,输出
           newpage = ret
           if newpage not in sites:
               print "Add New Page: " + newpage
               pages.add(newpage)
       return pages
    
    #dfs算法遍历全站
    def dfs(pages):
        #无法获取新的url说明便利完成,即可结束dfs
       if pages is set():
           return
       global url
       global domain
       global sites
       global visited
       sites = set.union(sites,pages)
       for page in pages:
           if page not in visited:
               print "Visiting",page
               visited.add(page)
               url = page
               pages = get_local_pages(url, domain)
               dfs(pages)
    
       print "sucess"
     #整段程序下来,一直不知道 变量domain用来检验获取的所有url是否是改域名下的
    
    pages = get_local_pages(url, domain)
    dfs(pages)
    for i in sites:
    print i
  • 相关阅读:
    lua与C++的绑定
    lua与C的绑定
    如何得到真实的需求?
    mysql学习笔记——对数据库的操作
    排列组合公式
    英语口语积累笔记
    初学C++-----------------类的组合
    初学C++-----------------类的拷贝构造函数
    初学C++-----------------类的构造函数、析构函数
    初学C++-----------------类的定义
  • 原文地址:https://www.cnblogs.com/092e/p/14917184.html
Copyright © 2011-2022 走看看