• Python开发简单爬虫


    本文在学习慕课网 疯狂的蚂蚁crazyant 的课程后写作,文中截图部分来自于视频,感谢视频作者。大家也可以通过点击这里观看视频学习,老师讲得贼棒!

    What's 爬虫

    通俗的讲,爬虫就是通过一个URL开始,自动获取数据的“网络机器人”。

    简单的爬虫架构

    pic

    1. URL管理器记录爬取过的URL和未爬取的URL
    2. 从URL管理器中获取一个未爬取的URL下载网页内容
    3. 解析爬取到的内容,将价值数据存储起来,将爬到的新URL传递给URL管理器存储为未爬取的URL,并从2开始循环执行

    URL管理器

    存储未爬取的URL和爬取过的URL

    作用

    • 防止重复抓取。爬取过后的URL存在已爬取URL集合中,不再去访问
    • 防止循环抓取。如果A网页包含B网页的链接,B网页包含A网页的链接,可能导致无限循环。每次添加URL时,判断未爬取URL集合、已爬取URL集合可以避免

    需要实现的功能

    • 可以添加新的URL到未爬取集合中,该功能需要判断新的URL是否在URL管理器容器中
    • 判断是否还有未爬取的URL
    • 获取一个待爬取的URL,该功能需要从未爬取的URL集合中删除该URL,并添加到已爬取的URL集合中

    实现方式

    • 使用Python,用两个Set分别表示
    • 使用Mysql等数据库存储
    • 使用Redis等,也可以使用两个Set分别表示

    网页下载器

    将互联网上URL对应的网页下载到本地的工具,本文介绍Python自带库“urllib2”

    "urllib2"使用方法

    1. 最简单的使用方法

      pic

    2. 添加data、http header

      pic

    3. 添加特殊情景的处理器(HTTPCookieProcessor、ProxyHandler、HTTPSHandler、HTTPRedirectHandler)

      以添加HTTPCookieProcessor为例:

      pic

    网页解析器

    网页解析器是从网页中提取有价值数据的工具。

    pic

    常见的几种网页解析器

    • 正则表达式:可以模糊匹配网页字符串里中的内容,在比较复杂的数据中非常麻烦
    • html.parser:Python自带的解析器
    • lxml:第三方插件,可以解析html和xml
    • Beautiful:第三方插件,它既可以使用html.parser作为解析器,也可以使用lxml作为解析器,功能比较强大,推荐使用

    其中,正则表达式是基于文本的模糊匹配;其他3种方式将网页文档解析为DOM树解析。

    pic

    Beautiful Soup介绍

    官网:https://www.crummy.com/software/BeautifulSoup/

    pic

    对Beautiful Soup进行操作的一般步骤

    1. 先根据HTML网页字符串创建Beautiful Soup对象。
    2. 获取节点,可以通过节点名称、属性值、文字搜索节点。find_all会搜索所有满足要求的节点,find搜索出满足要求的第一个节点。
    3. 访问节点,获取节点的名称、属性、文字的值。
      pic

    函数介绍

    1. 创建Beautiful Soup对象

      pic

    2. 搜索节点(find_all,find)

      pic

    3. 访问节点信息

      pic

    爬虫实例

    分析

    1. 确定目标

      也就是说:我们需要扒取哪个网站和哪些数据。

      本实例我们确定要抓取百度百科“python”词条这个页面和它相关的页面,数据包括页面内的关键词、简介。

    2. 分析目标

      • URL格式,用来限定抓取页面的范围

      本实例抓取的URL是页面中的其他词条的超链接,格式类似于<a href="/item/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%AD%E8%A8%80">计算机程序设计语言</a>

      • 抓取的数据格式,用于存储数据

      本实例都是字符串格式的数据

      • 确定编码,确保程序中的编码格式

      百度百科网页使用utf-8编码,所以在编写代码中注意转码

    3. 编写代码

    4. 执行爬虫

    编码

    主模块

    # -*- coding:utf-8 -*-
    
    import url_manager
    import html_downloader
    import html_parser
    import html_outputer
    
    
    class SpiderMain(object):
    
        def __init__(self):
            self.urls = url_manager.UrlManager() # 初始化URL管理器
            self.downloader = html_downloader.HtmlDownloader() # 初始化网页下载器
            self.parser = html_parser.HtmlParser() # 初始化网页解析器
            self.outputer = html_outputer.HtmlOutputer() # 初始化数据输出器
    
        def craw(self,root_url):
            count = 1  # 记录成功条数
            self.urls.add_new_url(root_url) # 添加url到url管理器
            while self.urls.has_new_url():
                try:
                    new_url = self.urls.get_new_url() # 获取未爬过的url
                    print 'craw %d : %s' %(count, new_url)
                    html_cont = self.downloader.download(new_url) # 根据url下载网页
                    new_urls, new_data = self.parser.parse(new_url, html_cont) # 解析网页内容
                    self.urls.add_new_urls(new_urls) # 将爬到的新网址添加到url管理器
                    self.outputer.collect_data(new_data) # 将内容添加到数据输出器
    
                    if count == 1000:
                        break
    
                    count = count + 1
                except:
                    print 'craw failed'
    
    
            self.outputer.output_html() # 输出内容
    
    # main函数
    if __name__ == '__main__':
        root_url = 'https://baike.baidu.com/item/Python' # 最开始的url
        obj_spider = SpiderMain()
        obj_spider.craw(root_url)
    

    URL管理器

    # -*- coding:utf-8 -*-
    
    # URL管理器
    class UrlManager(object):
    
        def __init__(self):
            self.new_urls = set() # 存放未读取url
            self.old_urls = set() # 存放已读取url
    
        # 添加一个url到未读url列表
        def add_new_url(self, url):
            if url is None:
                return
            if url not in self.new_urls and url not in self.old_urls:
                self.new_urls.add(url)
    
        # 添加多个url到未读url列表
        def add_new_urls(self, urls):
            if urls is None or len(urls) == 0:
                return
            for url in urls:
                self.add_new_url(url)
    
        # 返回是否有未读url
        def has_new_url(self):
            return len(self.new_urls) != 0
    
        # 随机获取一个未读url
        def get_new_url(self):
            new_url = self.new_urls.pop() # 获取未读url并删除
            self.old_urls.add(new_url) # 添加这个url到已读url列表中
            return new_url
    

    网页下载器

    # -*- coding:utf-8 -*-
    
    import urllib2
    
    # 网页下载器
    class HtmlDownloader(object):
    
        # 获取服务器响应内容
        def download(self,url):
            if url is None:
                return None
    
            response = urllib2.urlopen(url)
    
            if response.getcode() != 200: # 获取成功标识
                return None
    
            return response.read()
    
    

    网页解析器

    # -*- coding:utf-8 -*-
    from bs4 import BeautifulSoup
    import re
    
    # 网页解析器
    class HtmlParser(object):
    
        # 获取其中的url
        def __get_new_urls(self,page_url, soup):
            new_urls = set()
            links = soup.find_all('a', href=re.compile(r'/item/[a-zA-Z0-9%]+')) # 匹配url,可能会发生变化
            for link in links:
                new_url = link['href'].encode('utf-8') # 获取url
                new_full_url = 'https://baike.baidu.com'+new_url # 拼接url
                new_urls.add(new_full_url)
            return new_urls
    
        # 获取其中的内容(关键词,简介)
        def __get_new_data(self,page_url,soup):
            res_data = {}
    
            res_data['url'] = page_url
    
            # 获取关键词
            title_node = soup.find('dd', class_ = 'lemmaWgt-lemmaTitle-title').find('h1')
            res_data['title'] = title_node.get_text()
    
            # 获取简介
            summary_node = soup.find('div', class_ = 'lemma-summary')
            res_data['summary'] = summary_node.get_text()
    
            return res_data
    
        # 解析htnl字符串
        def parse(self,page_url,html_cont):
            if page_url is None or html_cont is None:
                return
    
            soup = BeautifulSoup(html_cont, 'html.parser', from_encoding='utf-8')
            new_urls = self.__get_new_urls(page_url, soup)
            new_data = self.__get_new_data(page_url, soup)
            return new_urls, new_data
    

    数据输出器

    # -*- coding:utf-8 -*-
    
    # 数据输出器
    class HtmlOutputer(object):
    
        def __init__(self):
            self.datas = list()
    
        # 添加数据到列表中
        def collect_data(self, data):
            if data is None:
                return
            self.datas.append(data)
    
        # 输出到html文件中
        def output_html(self):
            fout = open(r'output.html','w')
    
            fout.write('<html>')
            fout.write('<body>')
            fout.write('<table>')
    
    
    
            for data in self.datas:
                fout.write('<tr>')
                fout.write('<td>%s</td>' % data['url'])
                fout.write('<td>%s</td>' % data['title'].encode('utf-8'))
                fout.write('<td>%s</td>' % data['summary'].encode('utf-8'))
                fout.write('</tr>')
    
    
            fout.write('</table>')
            fout.write('</body>')
            fout.write('</html>')
    
            fout.close()
    
    

    文章除注明转载外,均为原创。欢迎任何形式的转载,但请务必注明出处:

    文章转载自 OSchina 开源中国
    本文作者:dotleo
    作者主页:https://my.oschina.net/u/2930289/blog

    转载于:https://my.oschina.net/u/2930289/blog/1531168

  • 相关阅读:
    PHP Mysql-插入多条数据
    PHP Mysql-插入数据
    PHP Mysql-创建数据表
    PHP Mysql-创建数据库
    PHP Mysql-连接
    PHP Mysql-简介
    PHP-7
    postgresql 创建函数
    在psql客户端中修改函数
    修改PostgreSQL数据库的默认用户postgres的密码
  • 原文地址:https://www.cnblogs.com/twodog/p/12139427.html
Copyright © 2020-2023  润新知