1 爬虫功能:

https://docs.python.org/zh-cn/3/

       

爬虫 blob 协议 video java下载 爬虫demo_python

 

 

2 代码实现

开发环境: python3.6

import os
import sys
import http.client      #2.7版本为httplib
import urllib.request
import formatter
import io


from html.parser import HTMLParser

class Retriever(object):
    __slots__ = ('url', 'file')

    def __init__(self,url):
        self.url, self.file = self.get_url_file(url)

    def get_url_file(self, url, default = 'index.html'):
        #'Create usable local filename from URL'
        parsed = urllib.request.urlparse(url)
        host = parsed.netloc.split('@')[-1].split(':')[0]
        print('retriever host: %s' %host)
        filepath = '%s%s' %( host, parsed.path)
        if not os.path.splitext(parsed.path)[1]:
            filepath = os.path.join(filepath, default)
        print('retriever filepath: %s' % filepath)
        linkdir = os.path.dirname(filepath)
        if not os.path.isdir(linkdir):
            if os.path.exists(linkdir):
                os.unlink(linkdir)
            os.makedirs(linkdir)
        return url, filepath

    def download(self):
        #'Download URL to specific named file'
        try:
            retval = urllib.request.urlretrieve(self.url,self.file)
        except (IOError,http.client.InvalidURL) as e:
            retval ( ('***ERROR: bad URL "%s" %s') %(self.url, e))
        return retval

    def parse_links(self):
        class AnchorParser(HTMLParser):
            def handle_starttag(self, tag, attrs):
                if tag != 'a':
                    return
                if not hasattr(self , 'data'):
                    self.data = []
                for attr in attrs:
                    if attr[0] == 'href':
                        self.data.append(attr[1])

        f = open(self.file, 'r', encoding="UTF-8")
        data = f.read()
        f.close()
        parser = AnchorParser()
        parser.feed(data)
        parser.close()
        #output( (urllib.request.join(self.url, x) for x in parser.data ) )
        if not hasattr(parser, 'data'):
            return []
        return parser.data

class Crawler(object):
    count = 0
    def __init__(self, url):
        self.q = [url]
        self.seen = set()
        parsed = urllib.request.urlparse(url)
        host = parsed.netloc.split('@')[-1].split(':')[0]
        print("host: %s" %host)
        #self.dom = '.'.join(host.split('.')[-2:])
        self.dom = host
        print("dom: %s" %self.dom)

    def get_page(self, url, media=False):
        r = Retriever(url)
        fname = r.download()[0]
        print('donwload file name: %s' %fname)
        if fname[0] == '*':
            print(fname + '...skipping parse')
            return
        Crawler.count += 1;
        print("(%d,URL:%s, FILE:%s)" %(Crawler.count, url, fname))
        self.seen.add(url)
        ftype = os.path.splitext(fname)[1]
        if ftype not in ('.html', 'htm'):
            return
        print(r.parse_links())

        for link in r.parse_links():
            if link.startswith('mailto:'):
                print('...discarded, mailto link')
                continue
            if not media:
                ftype = os.path.splitext(link)[1]
                if ftype in ('.mp3', '.mp4', '.m4v', '.wav'):
                    print( '...discard, media file')
                    continue
                if ftype in ('.epub'):
                    print('...discard, epub file')
                    continue
            if not link.startswith('http://') and not link.startswith('https://'):
                link = urllib.request.urljoin(url, link)
            print('*', link)
            if link not in self.seen:
                if self.dom not in link:
                    print('...discard,not in domain')
                else:
                    if link not in self.q:
                        self.q.append(link)
                        print('...new, added to Q')
                    else:
                        print('...discard, already in Q')
            else:
                print('...discarded, already processed')


    def go(self, media = False):
        #'Process next page in queue (if any) '
        while self.q:
            url = self.q.pop()
            self.get_page(url, media)

def main():
    if len(sys.argv) > 1:
        url = sys.argv[1]
    else:
        try:
            url = input('Entry starting URL: ')
        except(KeyboardInterrupt, KeyError):
            url = ''
    if not url:
        return
    if not url.startswith('http://') and \
        not url.startswith('https://'):
        url = 'http://%s/' %url

    print('start url: %s'  %url )

    robot = Crawler(url)
    robot.go()



if __name__ == '__main__':
    main()

 

 

 

3使用包包和函数

os.path

os.path.splitext

用法: os.path.splitext(“文件路径”)    分离文件名与扩展名;默认返回(fname,fextension)元组,可做分片操作

os.path.join

用法: 接两个或更多的路径名组件

                         1.如果各组件名首字母不包含’/’,则函数会自动加上

         2.如果有一个组件是一个绝对路径,则在它之前的所有组件均会被舍弃

         3.如果最后一个组件为空,则生成的路径以一个’/’分隔符结尾

os.path.dirname

语法:os.path.dirname(path) 
功能:去掉文件名,返回目录 

os.path.unlink

os.unlink(path) 方法用于删除文件,如果文件是一个目录则返回一个错误。

 

urllib.request

urllib.request.urlretrieve

python3中urllib.request模块提供的urlretrieve()函数。urlretrieve()方法直接将远程数据下载到本地。

urlretrieve(url, filename=None, reporthook=None, data=None)

参数url:下载链接地址
参数filename:指定了保存本地路径(如果参数未指定,urllib会生成一个临时文件保存数据。)
参数reporthook:是一个回调函数,当连接上服务器、以及相应的数据块传输完毕时会触发该回调,我们可以利用这个回调函数来显示当前的下载进度。
参数data:指post导服务器的数据,该方法返回一个包含两个元素的(filename, headers) 元组,filename 表示保存到本地的路径,header表示服务器的响应头

html.parse.HTMLParser

HTMLParser 类

  1. HTMLParser.feed(data):接收一个字符串类型的HTML内容,并进行解析
  2. HTMLParser.close():当遇到文件结束标签后进行的处理方法。如果子类要复写该方法,需要首先调用HTMLParser累的close()
  3. HTMLParser.reset():重置HTMLParser实例,该方法会丢掉未处理的html内容
  4. HTMLParser.getpos():返回当前行和相应的偏移量
  5. HTMLParser.handle_starttag(tagattrs):对开始标签的处理方法。例如<div id="main">,参数tag指的是div,attrs指的是一个(name,Value)的列表
  6. HTMLParser.handle_endtag(tag):对结束标签的处理方法。例如</div>,参数tag指的是div
  7. HTMLParser.handle_data(data):对标签之间的数据的处理方法。<tag>test</tag>,data指的是“test”
  8. HTMLParser.handle_comment(data):对HTML中注释的处理方

当然了,使用Python自带的HTMLParser还是比较麻烦的,需要手写处理Html标签的函数。