zoukankan      html  css  js  c++  java
  • python简单爬虫(二)

      

      上一篇简单的实现了获取url返回的内容,在这一篇就要第返回的内容进行提取,并将结果保存到html中。

    一 、 需求:

      抓取主页面:百度百科Python词条   https://baike.baidu.com/item/Python/407313

      

    分析上面的源码格式,便于提取:

    • 关键词分析:位于class为lemmaWgt-lemmaTitle-title的dd元素的第一个h1标签内

    •  简介分析(位于class为lemma-summary的div的text内容)

       

    • 其他相关联的标签的分析(是a标签,且href以/item/开头)

     

    二、抓取过程流程图:

     

     三、分析:

    1. 网页下载器:

    1.作用:

    将互联网上URL对应的网页以HTML形式下载到本地

    常用的本地下载器
      1、urllib2 Python官方基础模块
      2、requests 第三方包,功能更强大

     2.urllib下载网页的三种方法

     (1)URL传入urllib2.urlopen(url)方法

    import urllib2
    #直接请求
    response = urllib2.urlopen('http://www.baidu.com')
    
    #获取状态码,如果是200表示成功
    code = response.getcode()
    
    #读取内容
    cont = response.read()

     (2)添加data、http header

    将url、data、header传入urllib.Request方法
    然后 URLlib.urlopen(request)

    import urllib2
    
    #创建Request对象
    request = urllin2.Request(url)
    
    #添加数据
    request.add_data('a'.'1')
    
    #添加http的header 将爬虫程序伪装成Mozilla浏览器
    request.add_header('User-Agent','Mozilla/5.0')
    
    #发送请求获取结果
    response = urllib2.urlopen(request)

     (3)添加特殊情景的处理器

    处理用户登录才能访问的情况,添加Cookie
    或者需要代理才能访问 使用ProxyHandler
    或者需要使用https请求

    2.网页解析器

     1.作用:

    从网页中提取有价值数据的工具

    以HTML网页字符串为输入信息,输出有价值的数据和新的待爬取url列表

    网页解析器种类
      1、正则表达式 将下载好的HTML字符串用正则表达式匹配解析,适用于简单的网页解析 字符串形式的模糊匹配
      2、html.parser python自带模块
      3、BeautifulSoup 第三方插件
      4、xml 第三方插件

    原理是解析成DOM树:

     

     2.BeautifulSoup简介及使用方法:

     1.简介:

      BeautifulSoup:Python第三方库,用于从HTML或XML中提取数据

    安装并测试beautifulsoup

    方法1:-安装:pip install beautifulsoup4
        -测试:import bs4

    方法2:pycharm--File--settings--Project Interpreter--添加beautifulsoup4

     2.语法介绍:

    根据HTML网页字符串可以创建BeautifulSoup对象,创建好之后已经加载完DOM树
    即可进行节点搜索:find_all、find。搜索出所有/第一个满足要求的节点(可按照节点名称、属性、文字进行搜索)
    得到节点之后可以访问节点名称、属性、文字

    如:
    <a href="123.html" class="aaa">Python</a>
    可根据:
    节点名称:a
    节点属性:href="123.html" class="aaa"
    节点内容:Python

    创建BeautifulSoup对象:

    from bs4 import BeautifulSoup

    #根据下载好的HTML网页字符串创建BeautifulSoup对象
    soup = BeautifulSoup(
      html_doc, #HTML文档字符串
      'html.parser' #HTML解析器
      from_encoding='utf-8' #HTML文档编码
    )

    搜索节点:
    方法:find_all(name,attrs,string)

    #查找所有标签为a的节点
      soup.find_all('a')

    #查找所有标签为a,链接符合/view/123.html形式的节点
      soup.find_all('a',href='/view/123.html')
      soup.find('a',href=re.compile('aaa')) #用正则表达式匹配内容

    #查找所有标签为div,class为abc,文字为Python的节点
      soup.find_all('div',class_='abc',string='Python') #class是Python关键字 避免冲突

     由于class是python的关键字,所以讲class属性加了个下划线。


    访问节点信息:
      得到节点:<a href="123.html" class="aaa">Python</a>

    #获取查找到的节点的标签名称
      node.name
    #获取查找到的节点的href属性
      node['href']
    #获取查找到的节点的连接文字
      node.gettext()

    四、代码实现:

    spider.py

    # 爬虫的入口调度器
    from baike import url_manager, html_downloader, html_parser, html_outputer
    
    
    class SpiderMain(object):
        def __init__(self):
            self.urlManager = url_manager.UrlManager()
            self.downloader = html_downloader.HtmlDownLoader()
            self.parser = html_parser.HtmpParser()
            self.outputer = html_outputer.HtmlOutpter()
    
    
        def craw(self,url):
            count = 1 #定义爬取几个页面
            self.urlManager.add_new_url(url)
            while self.urlManager.has_new_url():
                try:
                    # 获取一个url
                    new_url = self.urlManager.get_new_url()
                    # 访问url,获取网站返回数据
                    html_content = self.downloader.download(new_url)
                    new_urls, new_datas = self.parser.parse(new_url, html_content)
                    self.urlManager.add_new_urls(new_urls)
                    self.outputer.collect_data(new_datas)
                    print(count)
                    if count == 5:
                        break
                    count = count+1
                except Exception as e:
                    print("发生错误",e)
            # 将爬取结果输出到html
            self.outputer.out_html()
    
    if __name__=="__main__":
        url = 'https://baike.baidu.com/item/Python/407313'
        sm = SpiderMain()
        sm.craw(url)

    url_manager.py

    # url管理器
    class UrlManager(object):
        def __init__(self):
            # 定义两个set,一个存放未爬取的url,一个爬取已经访问过的url
            self.new_urls = set()
            self.old_urls = set()
    
        # 添加一个url的方法
        def add_new_url(self,url):
            if url is None:
                return  None
            if url not in self.new_urls and url not in self.old_urls:
                self.new_urls.add(url)
    
        # 判断是否还有待爬取的url(根据new_urls的长度判断是否有待爬取的页面)
        def has_new_url(self):
            return len(self.new_urls) != 0
    
        # 定义获取一个新的url的方法
        def get_new_url(self):
            if len(self.new_urls)>0:
                # 从new_urls弹出一个并添加到old_urls中
                new_url = self.new_urls.pop()
                self.old_urls.add(new_url)
                return new_url
    
        # 批量添加url的方法
        def add_new_urls(self, new_urls):
            if new_urls is None:
                return
            for url in new_urls:
                self.add_new_url(url)

    html_downloader.py

    # 读取网页的类
    import urllib.request
    
    
    class HtmlDownLoader(object):
        def download(self, url):
            if url is None:
                return
            # 访问url
            response = urllib.request.urlopen(url)
            # 如果返回的状态码不是200代表异常
            if response.getcode() != 200:
                return
            return response.read()

    html_parser.py

    # 网页解析器类
    import re
    import urllib
    
    from bs4 import BeautifulSoup
    
    
    class HtmpParser(object):
        # 解析读取到的网页的方法
        def parse(self, new_url, html_content):
            if html_content is None:
                return
            soup = BeautifulSoup(html_content,'html.parser',from_encoding='utf-8')
            new_urls = self.get_new_urls(new_url,soup)
            new_datas = self.get_new_datas(new_url,soup)
            return new_urls, new_datas
    
    
        # 获取new_urls的方法
        def get_new_urls(self, new_url, soup):
            new_urls = set()
            # 查找网页的a标签,而且href包含/item
            links = soup.find_all('a',href=re.compile(r'/item'))
            for link in links:
                # 获取到a必去哦啊Ian的href属性
                url = link['href']
                # 合并url。使爬到的路径变为全路径,http://....的格式
                new_full_url = urllib.parse.urljoin(new_url,url)
                new_urls.add(new_full_url)
            return new_urls
    
    
    
        # 获取new_data的方法
        def get_new_datas(self, new_url, soup):
            new_datas = {}
            # 获取标题内容
            title_node = soup.find('dd',class_='lemmaWgt-lemmaTitle-title').find('h1')
            new_datas['title'] = title_node.get_text()
    
            #获取简介内容
            summary_node = soup.find('div',class_='lemma-summary')
            new_datas['summary'] = summary_node.get_text()
    
            new_datas['url'] = new_url
    
            return new_datas
    html_outputer.py
    class HtmlOutpter(object):
        # 构造方法
        def __init__(self):
            self.datas = []
    
        # 收集数据的方法
        def collect_data(self, new_datas):
            if new_datas is None:
                return
            # 如果数据不为空就讲数据添加datas集合中
            self.datas.append(new_datas)
    
        # 输出爬取到的数据到本地磁盘中
        def out_html(self):
            if self.datas is None:
                return
            file = open('C:\Users\liqiang\Desktop\实习\python\pythonCraw\out.html', 'w', encoding='utf-8')
            file.write("<html>")
            file.write("<head>")
            file.write("<title>爬取结果</title>")
            # 设置表格显示边框
            file.write(r'''
            <style>
             table{100%;table-layout: fixed;word-break: break-all; word-wrap: break-word;}
             table td{border:1px solid black;300px}
            </style>
            ''')
            file.write("</head>")
            file.write("<body>")
            file.write("<table cellpadding='0' cellspacing='0'>")
            # 遍历datas填充到表格中
            for data in self.datas:
                file.write("<tr>")
                file.write('<td><a href='+str(data['url'])+'>'+str(data['url'])+'</a></td>')
                file.write("<td>%s</td>" % data['title'])
                file.write("<td>%s</td>" % data['summary'])
                file.write("</tr>")
            file.write("</table>")
            file.write("</body>")
            file.write("</html>")

    运行spider.py的主函数:(结果会将提取到的结果保存到html中)

     总结:

      python的类类似于java,继承object

      python的返回值return和return None一样(None类似于java的null关键字)

  • 相关阅读:
    27. 为什么线程执行要调用start而不是直接run
    25. ThreadLocal的使用场景
    23. 线程如何退出结束
    20. Java字符串格式化方法
    21. 时间的格式化方法
    19. 用过spring的线程池还是java的线程池?
    17. zookeeper的实现机制,有缓存,如何存储注册服务的
    面试-spring 那些事
    Apache服务器和tomcat服务器有什么区别?
    JNDI 和JDBC的区别
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/8877705.html
Copyright © 2011-2022 走看看