python爬虫爬出新高度

转载 2017年09月10日 20:37:21

一、运行环境

     (1)win7

     (2)python 2.7

     (3)pycharm

二、获取csdn发表的文章

# coding:utf-8
import urllib2, re, time, random, os, datetime
import HTMLParser
from bs4 import BeautifulSoup
import sys

reload(sys)
sys.setdefaultencoding('utf-8')


# 自定义打印函数
def self_log(msg):
    print u'%s: %s' % (time.strftime('%Y-%m-%d %H:%M:%S'), msg)


# 获取页面内容
def get_html(url):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
    req = urllib2.Request(url=url, headers=headers)
    try:
        html = urllib2.urlopen(req).read()
        html = HTMLParser.HTMLParser().unescape(html)
        return html
    except urllib2.HTTPError, e:
        print e.code


# 得到博客页面总数
def get_last_page(html, fd):
    if not html:
        self_log(u'页面错误,停止运行')
        return
    page = BeautifulSoup(html, 'lxml')
    try:
        last_page = page.find('div', class_='pagelist').find_all('a')
        last_page = last_page[len(last_page) - 1].get('href')[-1:]
        self_log('总共有%s 页博客' % last_page)
        fd.write('总共有%s 页博客\n' % last_page)
        return last_page
    except Exception, e:
        return 1


        # 获取页面列表


def get_items(url):
    content_html = get_html(url)
    page = BeautifulSoup(content_html, 'lxml')
    items = page.find_all('div', class_='list_item list_view')
    return items


# 根据每一个items list 提取需要的元素
def handle_items(items, content_list, read_num_for_sort):
    for item in items:
        temp = {}  # 临时变量

        title = item.find('a')  # 标题
        content_url = 'http://blog.csdn.net' + title.get('href')  # 标题对应文章的地址
        read_times = item.find('span', class_='link_view').text.strip()  # 阅读次数
        comments_time = item.find('span', class_='link_comments')  # 评论次数

        read_number = int(filter(str.isdigit, str(read_times)))  # 提取出来具体阅读次数的数字,为之后的排序做准备
        read_num_for_sort.append(read_number)

        # 将数据打包
        temp['indexs'] = read_number
        temp['title'] = title.text.strip()
        temp['read_times'] = read_times
        temp['comments_time'] = comments_time.text.strip()
        temp['content_url'] = content_url
        content_list.append(temp)

        # 创建文件夹


def mkdir_folder(path):
    if not os.path.exists(path):
        os.makedirs(path)

        # 获取页面信息


def getContent(html, dir_path):
    page = BeautifulSoup(html, 'lxml')
    try:
        title = page.find('div', class_='article_title').find('a').text
        title = title.strip()
    except Exception, e:
        print e
    try:
        content = page.find('div', class_='article_content')
        dir_path = dir_path
        artitle_name_path = dir_path + '/' + title + '.txt'
        with open(artitle_name_path + '.txt', 'w') as f:
            f.write(content.text)
        self_log(u'存贮文章:%s 完毕' % title)
    except Exception, e:
        print e

        # 存贮每一篇文章到本地


def run_to_get_article(content_total_list, dir_path):
    self_log('start save every article  ')
    for article_content in content_total_list:
        article_url = article_content.split('|')[4]
        self_log('将要存贮的地址是: %s ...' % article_url)
        artitle_html = get_html(article_url)
        getContent(artitle_html, dir_path)

        # 根据传进来的地址,获取博主名字,同时以博主名字命名存贮目录


def get_blocker_name(url):
    if 'viewmode' in url:
        print url.split('.net')[1]
        print url.split('.net')[1].split('?')[0].split('/')[1]
        return url.split('.net')[1].split('?')[0].split('/')[1]
    else:
        print url.split('.net')[1]
        print url.split('.net')[1].split('/')[1]
        return url.split('.net')[1].split('/')[1]
        # 程序运行主函数


def run(url, dir_path):
    read_num_for_sort = []
    content_list = []
    content_total_list = []

    # 定义文件夹名字并创建文件夹
    dir_path = dir_path
    mkdir_folder(dir_path)

    # 定义文件名字
    count_file_name = dir_path + '/' + datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S') + '.txt'
    fd = open(count_file_name, 'w')

    # 1.从主页进入获取页面总数
    main_html = get_html(url)
    last_page = get_last_page(main_html, fd)

    if last_page > 1:
        # 3.组装url,分别加载每页的页面,同时在每一个页面提取我们需要的内容
        for i in range(1, int(last_page) + 1):
            if 'category' not in url:
                main_url = url.split('?')[0] + '/article/list/%d?viewmode=contents' % i
            else:
                main_url = url + '/%s' % i
            self_log('即将获取第%d页的内容,地址是:%s' % (i, main_url))

            items = get_items(main_url)  # 获取每一页的页面内容,根据页面内容得到文章item list
            handle_items(items, content_list, read_num_for_sort)  # 处理item list
    else:
        items = get_items(url)  # 获取每一页的页面内容,根据页面内容得到文章item list
        handle_items(items, content_list, read_num_for_sort)  # 处理item list
    self_log('总共有%d 篇文章' % len(content_list))  # 根据得到的数据,统计文章总数
    # 根据 indexs(阅读次数)这个索引值进行排序
    # 非常好的一个根据列表中字典数据进行排序的方法
    content_list = sorted(content_list, cmp=lambda x, y: cmp(x['indexs'], y['indexs']), reverse=0)

    article_index = 1
    for a in content_list:
        # 组装打印语句
        totalcontent = '第' + str(article_index) + '篇|' + a['title'] + '|' + a['read_times'] + '|' + a[
            'comments_time'] + '|' + a['content_url']
        # self_log(totalcontent)
        print totalcontent
        # 将其存贮到本地
        fd.write(totalcontent)
        fd.write('\n')
        article_index += 1
        content_total_list.append(totalcontent)
    fd.close()

    return content_total_list


if __name__ == '__main__':
    print '''
            *****************************************  
            **    Welcome to Spider of Count CSDN  **
            *****************************************
			'''
    #url = 'http://blog.csdn.net/qiqiyingse?viewmode=contents'
    url ='http://blog.csdn.net/zuochao_2013?viewmode=list'
    # url='http://blog.csdn.net/qiqiyingse/article/category/6292432?viewmode=contents'
    # url='http://blog.csdn.net/zuoxiaolong8810/article/category/1434962?viewmode=contents'
    dir_path = get_blocker_name(url)
    content_total_list = run(url, dir_path)
    run_to_get_article(content_total_list, dir_path)

二、爬去微信公众号内容

# coding: utf-8

'''
总的来说就是通过搜狗搜索中的微信搜索入口来爬取
'''

# 这三行代码是防止在python2上面编码错误的,在python3上面不要要这样设置
import sys

reload(sys)
sys.setdefaultencoding('utf-8')

from urllib import quote
from pyquery import PyQuery as pq
from selenium import webdriver
from pyExcelerator import *  # 导入excel相关包

import requests
import time
import re
import json
import os


class weixin_spider:
    def __init__(self, keywords):
        ' 构造函数 '
        self.keywords = keywords
        # 搜狐微信搜索链接入口
        # self.sogou_search_url = 'http://weixin.sogou.com/weixin?type=1&query=%s&ie=utf8&_sug_=n&_sug_type_=' % quote(self.keywords)
        self.sogou_search_url = 'http://weixin.sogou.com/weixin?type=1&query=%s&ie=utf8&s_from=input&_sug_=n&_sug_type_=' % quote(
            self.keywords)

        # 爬虫伪装头部设置
        self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'}

        # 设置操作超时时长
        self.timeout = 5

        # 爬虫模拟在一个request.session中完成
        self.s = requests.Session()

        # excel 第一行数据
        self.excel_data = [u'编号', u'时间', u'文章标题', u'文章地址', u'文章简介']
        # 定义excel操作句柄
        self.excle_w = Workbook()

    # 搜索入口地址,以公众为关键字搜索该公众号
    def get_search_result_by_keywords(self):
        self.log('搜索地址为:%s' % self.sogou_search_url)
        return self.s.get(self.sogou_search_url, headers=self.headers, timeout=self.timeout).content

    # 获得公众号主页地址
    def get_wx_url_by_sougou_search_html(self, sougou_search_html):
        doc = pq(sougou_search_html)
        # print doc('p[class="tit"]')('a').attr('href')
        # print doc('div[class=img-box]')('a').attr('href')
        # 通过pyquery的方式处理网页内容,类似用beautifulsoup,但是pyquery和jQuery的方法类似,找到公众号主页地址
        return doc('div[class=txt-box]')('p[class=tit]')('a').attr('href')

    # 使用webdriver 加载公众号主页内容,主要是js渲染的部分
    def get_selenium_js_html(self, url):
        browser = webdriver.PhantomJS()
        browser.get(url)
        time.sleep(3)
        # 执行js得到整个页面内容
        html = browser.execute_script("return document.documentElement.outerHTML")
        return html

    # 获取公众号文章内容
    def parse_wx_articles_by_html(self, selenium_html):
        doc = pq(selenium_html)
        print '开始查找内容msg'
        return doc('div[class="weui_media_box appmsg"]')

    # 有的公众号仅仅有10篇文章,有的可能多一点
    # return doc('div[class="weui_msg_card"]')#公众号只有10篇文章文章的


    # 将获取到的文章转换为字典
    def switch_arctiles_to_list(self, articles):
        # 定义存贮变量
        articles_list = []
        i = 1

        # 以当前时间为名字建表
        excel_sheet_name = time.strftime('%Y-%m-%d')
        excel_content = self.excle_w.add_sheet(excel_sheet_name)

        # 遍历找到的文章,解析里面的内容
        if articles:
            for article in articles.items():
                self.log(u'开始整合(%d/%d)' % (i, len(articles)))
                # 处理单个文章
                articles_list.append(self.parse_one_article(article, i, excel_content))
                i += 1
        return articles_list

    # 解析单篇文章
    def parse_one_article(self, article, i, excel_content):
        article_dict = {}

        # 获取标题
        title = article('h4[class="weui_media_title"]').text()
        self.log('标题是: %s' % title)
        # 获取标题对应的地址
        url = 'http://mp.weixin.qq.com' + article('h4[class="weui_media_title"]').attr('hrefs')
        self.log('地址为: %s' % url)
        # 获取概要内容
        summary = article('.weui_media_desc').text()
        self.log('文章简述: %s' % summary)
        # 获取文章发表时间
        date = article('.weui_media_extra_info').text()
        self.log('发表时间为: %s' % date)
        # 获取封面图片
        pic = self.parse_cover_pic(article)
        # 获取文章内容
        content = self.parse_content_by_url(url).html()
        # 存储文章到本地
        contentfiletitle = self.keywords + '/' + title + '_' + date + '.html'
        self.save_content_file(contentfiletitle, content)

        # 将这些简单的信息保存成excel数据
        cols = 0
        tempContent = [i, date, title, url, summary]
        for data in self.excel_data:
            excel_content.write(0, cols, data)
            excel_content.write(i, cols, tempContent[cols])

            cols += 1
        self.excle_w.save(self.keywords + '/' + self.keywords + '.xls')

        # 返回字典数据
        return {
            'title': title,
            'url': url,
            'summary': summary,
            'date': date,
            'pic': pic,
            'content': content
        }

    # 查找封面图片,获取封面图片地址
    def parse_cover_pic(self, article):
        pic = article('.weui_media_hd').attr('style')

        p = re.compile(r'background-image:url\((.*?)\)')
        rs = p.findall(pic)
        self.log('封面图片是:%s ' % rs[0] if len(rs) > 0 else '')

        return rs[0] if len(rs) > 0 else ''

    # 获取文章页面详情
    def parse_content_by_url(self, url):
        page_html = self.get_selenium_js_html(url)
        return pq(page_html)('#js_content')

    # 存储文章到本地
    def save_content_file(self, title, content):
        with open(title, 'w') as f:
            f.write(content)

    # 存贮json数据到本地
    def save_file(self, content):
        ' 数据写入文件 '
        with open(self.keywords + '/' + self.keywords + '.txt', 'w') as f:
            f.write(content)

    # 自定义log函数,主要是加上时间
    def log(self, msg):
        print u'%s: %s' % (time.strftime('%Y-%m-%d %H:%M:%S'), msg)

    # 验证函数
    def need_verify(self, selenium_html):
        ' 有时候对方会封锁ip,这里做一下判断,检测html中是否包含id=verify_change的标签,有的话,代表被重定向了,提醒过一阵子重试 '
        return pq(selenium_html)('#verify_change').text() != ''

    # 创建公众号命名的文件夹
    def create_dir(self):
        if not os.path.exists(self.keywords):
            os.makedirs(self.keywords)

            # 爬虫主函数

    def run(self):
        ' 爬虫入口函数 '
        # Step 0 :  创建公众号命名的文件夹
        self.create_dir()

        # Step 1:GET请求到搜狗微信引擎,以微信公众号英文名称作为查询关键字
        self.log(u'开始获取,微信公众号英文名为:%s' % self.keywords)
        self.log(u'开始调用sougou搜索引擎')
        sougou_search_html = self.get_search_result_by_keywords()

        # Step 2:从搜索结果页中解析出公众号主页链接
        self.log(u'获取sougou_search_html成功,开始抓取公众号对应的主页wx_url')
        wx_url = self.get_wx_url_by_sougou_search_html(sougou_search_html)
        self.log(u'获取wx_url成功,%s' % wx_url)

        # Step 3:Selenium+PhantomJs获取js异步加载渲染后的html
        self.log(u'开始调用selenium渲染html')
        selenium_html = self.get_selenium_js_html(wx_url)

        # Step 4: 检测目标网站是否进行了封锁
        if self.need_verify(selenium_html):
            self.log(u'爬虫被目标网站封锁,请稍后再试')
        else:
            # Step 5: 使用PyQuery,从Step 3获取的html中解析出公众号文章列表的数据
            self.log(u'调用selenium渲染html完成,开始解析公众号文章')
            articles = self.parse_wx_articles_by_html(selenium_html)
            self.log(u'抓取到微信文章%d篇' % len(articles))

            # Step 6: 把微信文章数据封装成字典的list
            self.log(u'开始整合微信文章数据为字典')
            articles_list = self.switch_arctiles_to_list(articles)

            # Step 7: 把Step 5的字典list转换为Json
            self.log(u'整合完成,开始转换为json')
            data_json = json.dumps(articles_list)

            # Step 8: 写文件
            self.log(u'转换为json完成,开始保存json数据到文件')
            self.save_file(data_json)

            self.log(u'保存完成,程序结束')


# main
# 几个可供参考的公众号
# DataBureau
# python6359
# ArchNotes
if __name__ == '__main__':
    print '''
			*****************************************
			**    Welcome to Spider of 公众号       **
			*****************************************
	'''
    gongzhonghao = raw_input(u'输入要爬取的公众号')
    if not gongzhonghao:
        gongzhonghao = 'python6359'
    weixin_spider(gongzhonghao).run()


三、爬去微信公众号内容制作词云

      (1)weixin_spider.py

# coding: utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

from urllib import quote
from pyquery import PyQuery as pq
from selenium import webdriver

import requests
import time
import re
import json
import os


# 搜索入口地址,以公众为关键字搜索该公众号
def get_search_result_by_keywords(sogou_search_url):
    # 爬虫伪装头部设置
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'}

    # 设置操作超时时长
    timeout = 5
    # 爬虫模拟在一个request.session中完成
    s = requests.Session()
    log(u'搜索地址为:%s' % sogou_search_url)
    return s.get(sogou_search_url, headers=headers, timeout=timeout).content


# 获得公众号主页地址
def get_wx_url_by_sougou_search_html(sougou_search_html):
    doc = pq(sougou_search_html)
    return doc('div[class=txt-box]')('p[class=tit]')('a').attr('href')


# 使用webdriver 加载公众号主页内容,主要是js渲染的部分
def get_selenium_js_html(url):
    browser = webdriver.PhantomJS(executable_path=r'H:\python\phantomjs.exe')

    browser.get(url)
    time.sleep(3)
    # 执行js得到整个页面内容
    html = browser.execute_script("return document.documentElement.outerHTML")
    browser.close()
    return html


# 获取公众号文章内容
def parse_wx_articles_by_html(selenium_html):
    doc = pq(selenium_html)
    return doc('div[class="weui_media_box appmsg"]')


# 将获取到的文章转换为字典
def switch_arctiles_to_list(articles):
    # 定义存贮变量
    articles_list = []
    i = 1

    # 遍历找到的文章,解析里面的内容
    if articles:
        for article in articles.items():
            log(u'开始整合(%d/%d)' % (i, len(articles)))
            # 处理单个文章
            articles_list.append(parse_one_article(article))
            i += 1
    return articles_list


# 解析单篇文章
def parse_one_article(article):
    article_dict = {}

    # 获取标题
    title = article('h4[class="weui_media_title"]').text().strip()
    ###log(u'标题是: %s' % title)
    # 获取标题对应的地址
    url = 'http://mp.weixin.qq.com' + article('h4[class="weui_media_title"]').attr('hrefs')
    log(u'地址为: %s' % url)
    # 获取概要内容
    summary = article('.weui_media_desc').text()
    log(u'文章简述: %s' % summary)
    # 获取文章发表时间
    date = article('.weui_media_extra_info').text().strip()
    log(u'发表时间为: %s' % date)
    # 获取封面图片
    pic = parse_cover_pic(article)

    # 返回字典数据
    return {
        'title': title,
        'url': url,
        'summary': summary,
        'date': date,
        'pic': pic
    }


# 查找封面图片,获取封面图片地址
def parse_cover_pic(article):
    pic = article('.weui_media_hd').attr('style')

    p = re.compile(r'background-image:url\((.*?)\)')
    rs = p.findall(pic)
    log(u'封面图片是:%s ' % rs[0] if len(rs) > 0 else '')

    return rs[0] if len(rs) > 0 else ''


# 自定义log函数,主要是加上时间
def log(msg):
    print u'%s: %s' % (time.strftime('%Y-%m-%d_%H-%M-%S'), msg)


# 验证函数
def need_verify(selenium_html):
    ' 有时候对方会封锁ip,这里做一下判断,检测html中是否包含id=verify_change的标签,有的话,代表被重定向了,提醒过一阵子重试 '
    return pq(selenium_html)('#verify_change').text() != ''


# 创建公众号命名的文件夹
def create_dir(keywords):
    if not os.path.exists(keywords):
        os.makedirs(keywords)

        # 爬虫主函数


def run(keywords):
    ' 爬虫入口函数 '
    # Step 0 :  创建公众号命名的文件夹
    create_dir(keywords)

    # 搜狐微信搜索链接入口
    sogou_search_url = 'http://weixin.sogou.com/weixin?type=1&query=%s&ie=utf8&s_from=input&_sug_=n&_sug_type_=' % quote(
        keywords)

    # Step 1:GET请求到搜狗微信引擎,以微信公众号英文名称作为查询关键字
    log(u'开始获取,微信公众号英文名为:%s' % keywords)
    log(u'开始调用sougou搜索引擎')
    sougou_search_html = get_search_result_by_keywords(sogou_search_url)

    # Step 2:从搜索结果页中解析出公众号主页链接
    log(u'获取sougou_search_html成功,开始抓取公众号对应的主页wx_url')
    wx_url = get_wx_url_by_sougou_search_html(sougou_search_html)
    log(u'获取wx_url成功,%s' % wx_url)

    # Step 3:Selenium+PhantomJs获取js异步加载渲染后的html
    log(u'开始调用selenium渲染html')
    selenium_html = get_selenium_js_html(wx_url)

    # Step 4: 检测目标网站是否进行了封锁
    if need_verify(selenium_html):
        log(u'爬虫被目标网站封锁,请稍后再试')
    else:
        # Step 5: 使用PyQuery,从Step 3获取的html中解析出公众号文章列表的数据
        log(u'调用selenium渲染html完成,开始解析公众号文章')
        articles = parse_wx_articles_by_html(selenium_html)
        log(u'抓取到微信文章%d篇' % len(articles))

        # Step 6: 把微信文章数据封装成字典的list
        log(u'开始整合微信文章数据为字典')
        articles_list = switch_arctiles_to_list(articles)
        return [content['title'] for content in articles_list]


  (2)weixin_wordcloud.py

# coding: utf8
from wordcloud import WordCloud
import weixin_spider
import matplotlib.pyplot as plt
import time

if __name__ == '__main__':
    print u'''
            ****************************************************************
            **   Welcome to Spider of weixin gongzhonghao for wordcloud   **
            ****************************************************************
    '''
    gongzhonghao = raw_input(u'input weixin gongzhonghao:')
    if not gongzhonghao:
        gongzhonghao = 'python'
    text = " ".join(weixin_spider.run(gongzhonghao))

    print text
    wordcloud = WordCloud(random_state=1, font_path=r'C:/Users/Windows/fonts/simkai.ttf').generate(
        text)  # 处理获取到的title,准备绘制词云

    print 'start drawing.....'
    plt.figure()
    plt.imshow(wordcloud, interpolation='bilinear')
    plt.axis('off')
    plt.show()


转载出处: http://blog.csdn.net/column/details/15501.html

Python爬虫定时增量更新数据

用户体验的工作可以说是用户需求和用户认知的分析。而消费者的声音是其中很重要的一环,它包含了用户对产品的评论,不管是好的坏的,都将对我们产品的改进和迭代有帮助。另外任何事情都要考虑金钱成本和人力成本,因...
  • yubei2155
  • yubei2155
  • 2018-02-21 19:48:15
  • 698

Python实现简单的爬虫获取某刀网的更新数据

昨天晚上无聊时,想着练习一下Python所以写了一个小爬虫获取小刀娱乐网里的更新数据#!/usr/bin/python # coding: utf-8 import urllib.request i...
  • u010834767
  • u010834767
  • 2017-04-10 15:08:19
  • 1091

Python爬虫练习:爬取csdn极客的更新文章

写在前面:这两周花了点时间读了《Python网络数据采集》,内容不多,不到200页,但是非常丰富,有入门,有提高,有注意事项,有经验之谈,有原理,有分析,读完受益匪浅。书中讲了很多反爬虫、图片验证码之...
  • blwinner
  • blwinner
  • 2018-01-25 15:18:57
  • 253

jquery 获取 outerHtml

在开发过程中,jQuery.html() 是获取当前节点下的html代码,并不包含当前节点本身的代码,然后我们有时候确需要,找遍jQuery api文档也没有任何方法可以拿到。 看到有的人通过par...
  • default7
  • default7
  • 2014-10-30 14:50:59
  • 8534

Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容

在Python网络爬虫内容提取器一文我们详细讲解了核心部件:可插拔的内容提取器类gsExtractor。本文记录了确定gsExtractor的技术路线过程中所做的编程实验。...
  • fullerhua
  • fullerhua
  • 2016-05-19 14:31:42
  • 2961

Python 三种网页抓取方法

摘要:本文讲的是利用Python实现网页数据抓取的三种方法;分别为正则表达式(re)、BeautifulSoup模块和lxml模块。本文所有代码均是在python3.5中运行的。 本文抓取的是[中...
  • wangxw_lzu
  • wangxw_lzu
  • 2017-07-13 21:08:09
  • 221

innerHTML,innerText,outerHTML用法及区别

test.innerHTML:   也就是从对象的起始位置到终止位置的全部内容,包括Html标签。   上例中的test.innerHTML的值也就是“test1 test2 ”。 tes...
  • tolcf
  • tolcf
  • 2014-08-15 15:23:59
  • 1024

python爬虫(17)爬出新高度_抓取微信公众号文章(selenium+phantomjs)(上)

抓取微信公众号的文章 一.思路分析 目前所知晓的能够抓取的方法有: 1、微信APP中微信公众号文章链接的直接抓取(http://mp.weixin.qq.com/s?__biz=MjM5MzU4OD...
  • qiqiyingse
  • qiqiyingse
  • 2017-04-11 12:09:34
  • 25168

python读取日志

场景:周一到周五早上6点半检查日志中的关键字,并发送相应的成功或者失败短信用python27版本实现...
  • shirayukixue
  • shirayukixue
  • 2016-08-04 16:02:45
  • 2915
收藏助手
不良信息举报
您举报文章:python爬虫爬出新高度
举报原因:
原因补充:

(最多只允许输入30个字)