python爬虫Demo
1 爬虫功能:
爬取某域名下所有网页,比如爬取python文档 https://docs.python.org/zh-cn/3/ ,爬取之后,获取离线文档

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 类
- HTMLParser.feed(data):接收一个字符串类型的HTML内容,并进行解析
HTMLParser.close():当遇到文件结束标签后进行的处理方法。如果子类要复写该方法,需要首先调用HTMLParser累的close()HTMLParser.reset():重置HTMLParser实例,该方法会丢掉未处理的html内容HTMLParser.getpos():返回当前行和相应的偏移量HTMLParser.handle_starttag(tag, attrs):对开始标签的处理方法。例如<div id="main">,参数tag指的是div,attrs指的是一个(name,Value)的列表HTMLParser.handle_endtag(tag):对结束标签的处理方法。例如</div>,参数tag指的是divHTMLParser.handle_data(data):对标签之间的数据的处理方法。<tag>test</tag>,data指的是“test”HTMLParser.handle_comment(data):对HTML中注释的处理方
当然了,使用Python自带的HTMLParser还是比较麻烦的,需要手写处理Html标签的函数。

浙公网安备 33010602011771号