百度百科词条内容爬取-爬虫大作业

实现过程

一、前期准备

首先打开要爬取的页面,作为根源页面。

我这里使用的百度百科的PHP词条,网址为https://baike.baidu.com/item/PHP/9337?fr=aladdin&fromid=6717846&fromtitle=%EF%BC%B0%EF%BC%A8%EF%BC%B0

然后选取其中适合收集信息的文字内容,右键审查。

 

可以发现该词条内关联的词条(url)非常多

装好软件和相关第三方库,开搞♂。

环境如下:

  python3.6.2    PyCharm

  Windows10    第三方库(jieba,wordcloud,bs4,Requests,re)

 

二、写代码

爬虫的架构大致如下

 

第一步先写个main来做调度,列好要实现的功能。

    def __init__(self):
        self.urls=url_manager.UrlManager() #url管理器
        self.downloader=html_downloader.HtmlDownloader()#下载器
        self.parser=html_parser.HtmlParser()#解析
        self.outputer=html_outputer.HtmlOutouter()#输出

  然后写

    def craw(self,root_url):
        count=1
        self.urls.add_new_url(root_url)
        while self.urls.has_new_url():
            try:
                new_url=self.urls.get_new_url()
                print('craw %d:%s'%(count,new_url))
                html_cont=self.downloader.download(new_url)
                new_urls,new_data=self.parser.parse(new_url,html_cont)
                self.urls.add_new_urls(new_urls)
                self.outputer.collest_data(new_data)
                if count>500:
                    break

                count+=1

            except Exception as e:
                print(str(e))

            self.outputer.output_html()



if __name__=="__main__":
    root_url='https://baike.baidu.com/item/PHP/9337?fr=aladdin&fromid=6717846&fromtitle=%EF%BC%B0%EF%BC%A8%EF%BC%B0'
    obj_spider=SpiderMain()
    obj_spider.craw(root_url)

  url管理器

class UrlManager(object):
    def __init__(self):
        self.new_urls =set()
        self.old_urls = set()

    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)

    def add_new_urls(self,urls):
        if urls is None or len(urls)==0:
            return
        for url in urls:
            self.add_new_url(url)

    def has_new_url(self):
        return len(self.new_urls)!=0

    def get_new_url(self):
        new_url = self.new_urls.pop()
        self.old_urls.add(new_url)
        return new_url

  接下来写下载器

class HtmlDownloader(object):
    def download(self,url):
        if url is None:
            return None

        url_ =quote(url,safe=string.printable)
        response =request.urlopen(url_)

        if response.getcode()!=200:
            return None

        return response.read()

  解析器来一个,百度百科链接的规律是baike.baidu.com/item/*

from bs4 import  BeautifulSoup
import re
import urllib.parse
class HtmlParser(object):
    def _get_new_urls(self, page_url, soup):
        new_urls = set()
        links=soup.find_all('a',href=re.compile(r"/item/"))

        for link in links:
            new_url = link['href']
            new_full_url=urllib.parse.urljoin(page_url,new_url)
            new_urls.add(new_full_url)
        return new_urls

    def _get_new_data(self, page_url, soup):
        res_data = {}

        # url
        res_data['url'] = page_url

        title_node = soup.find('dd', class_='lemmaWgt-lemmaTitle-title').find('h1')
        res_data['title'] = title_node.get_text()

        # <div class="lemma-summary" label-module="lemmaSummary">
        summary_node = soup.find('div', class_='lemma-summary')
        if summary_node is None:
            return
        res_data['summary'] = summary_node.get_text()

        #<div class="para" label-module="para">
        para_node = soup.find('div', class_='para')
        if para_node is None:
            return
        res_data['para'] = para_node.get_text()

        return res_data

    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

  输出到一个叫output.txt的文件

# -*- coding: UTF-8 -*-
class HtmlOutouter(object):
    def __init__(self):
        self.datas=[]

    def collest_data(self, new_data):
        if new_data is None:
            return
        self.datas.append(new_data)

    def output_html(self):
        fout=open('output.txt','w',encoding='utf-8')


        for data in self.datas:

            fout.write('%s' % ( data['title']))
            fout.write('%s' % data['para'])
            fout.write('%s' % data['summary'])


        fout.close()

  

得到txt文件一个

里面有爬了五百个url搞到手的文字内容。

 

三、生成词云

装词云库时有点小麻烦,下面再说。

#通过jieba分词进行分词并通过空格分隔
wordlist_after_jieba = jieba.cut(text_from_file_with_apath, cut_all = True)
wl_space_split = " ".join(wordlist_after_jieba)
#my_wordcloud = WordCloud().generate(wl_space_split) 默认构造函数
my_wordcloud = WordCloud(
            background_color='white',    # 设置背景颜色
            mask = abel_mask,        # 设置背景图片
            max_words = 800,            # 设置最大现实的字数
            stopwords = {}.fromkeys(['以及', '就是','可以','简称','位于','称为','之一','包括','一种','主要']),        # 设置停用词
            font_path = 'C:/Users/Windows/fonts/simkai.ttf',# 设置字体格式,如不设置显示不了中文
            max_font_size = 50,            # 设置字体最大值
            random_state = 30,            # 设置有多少种随机生成状态,即有多少种配色方案
                scale=.5
                ).generate(wl_space_split)

# 根据图片生成词云颜色
image_colors = ImageColorGenerator(abel_mask)

  调用,运行

背景图为

 

生成的词云图为

 

完成

 

遇到的问题及解决办法

1.word cloud安装失败,根据错误报告提示缺少vs c++构建工具。通过安装一个vs2017解决

2.一开始是打算爬百度贴吧的,但是爬百度贴吧的时候IP被拉黑了。本来打算通过动态IP的方式,但是没成功。所以去爬百度百科了。

3.词云生成的图片过于模糊,文字看不清楚。多次尝试发现跟原图的分辨率有关,换张分辨率高的图片获得不错的效果。

4.词云中无意义的词(如连接词等)太多。没搞到常用stopwords文件(csdn要三个积分),只能手动加了几个无意义的过滤词。

5.Windows10的字体文件格式是TTC,兼容TTF,使用ttf字体文件有一定概率失常。

6.尽量使用纯白色背景的图片来当背景图,不然根本看不出轮廓。

7.url,class后面要加_,不然一堆报错。

 

总结

写这个爬虫的时候暴露出了我的python基础很不好,需要再学好python。

爬虫是很有趣的东西,我会继续去学习更深入、更厉害的知识技能。

 

posted @ 2018-04-21 15:33  235郑杰升  阅读(2279)  评论(0编辑  收藏  举报