目的意义

基础爬虫分5个模块,使用多个文件相互配合,实现一个相对完善的数据爬取方案,便于以后更完善的爬虫做准备。

这里目的是爬取200条百度百科信息,并生成一个html文件,存储爬取的站点,词条,解释。

本文思路来源书籍。其代码部分来源书籍。https://book.douban.com/subject/27061630/

功能模块

主文件:爬虫调度器,通过调用其他文件中的方法,完成最终功能实现。

其他文件:URL管理器HTML下载器HTML解析器数据存储器

设计思路

定义SpiderMan类作为爬虫调度器。输入根URL开始爬取数据然后爬取结束。

在爬取过程中,需要获取网页,和解析网页。

解析网页需要HTML解析器,获取网页需要HTML下载器

解析网页需要解析的数据有:URL,TITLE,CONTEXT等。则需要URL管理器数据存储器

主文件设计

主文件添加根URL,然后提取该URL,下载该URL内容。

根据内容,调用解析器:

      解析出该URL中的新URL,存入URL管理器;

      解析出该URL中的标题,文本等信息,存入数据存储器。

完成后开始下一次。这时URL管理器多出了新的URL,提取出新的URL,下载,解析,不断重复即可。

重复结束以提取出的URL数量超过200则结束。

代码如下:

  1. from BaseSpider.DataOutput import DataOutput
  2. from BaseSpider.HtmlDownloader import HtmlDownloader
  3. from BaseSpider.HtmlParser import HtmlParser
  4. from BaseSpider.UrlManager import UrlManager
  5. class SpiderMan():
  6. def __init__(self):
  7. self.manager=UrlManager()
  8. self.downloader=HtmlDownloader()
  9. self.parser=HtmlParser()
  10. self.output=DataOutput()
  11.  
  12. def crawl(self,root_url):
  13. self.manager.add_new_url(root_url)
  14. while(self.manager.has_new_url() and self.manager.old_url_size()<200):
  15. new_url=self.manager.get_new_url()
  16. text=self.downloader.download(new_url)
  17. if text is None:
  18. print('None text')
  19. break
  20. new_urls,data=self.parser.parser(new_url,text)
  21. self.manager.add_new_urls(new_urls)
  22. self.output.store_data(data)
  23. print(self.manager.old_url_size())
  24. self.output.output_html()
  25.  
  26. if __name__ == "__main__":
  27. spider_man=SpiderMan()
  28. spider_man.crawl("https://baike.baidu.com/item/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/5162711?fr=aladdin")
  29. print('finish')

作为最初的设计,应该允许异常抛出,便于查看程序终止的原因,然后排查错误。

HTML下载器设计

下载网页,返回文本。即可。

  1. import requests
  2. import chardet
  3. class HtmlDownloader(object):
  4. def download(self,url):
  5. if url is None:
  6. return None
  7. user_agent='Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0'
  8. headers={'User-Agent':user_agent}
  9. r=requests.get(url,headers=headers)
  10. if r.status_code is 200:
  11. r.encoding=chardet.detect(r.content)['encoding']
  12. return r.text
  13. return None

HTML解析器设计

HTML解析器将下载的文本进行解析,需要解析出的数据有:页面的新URL页面的新数据文本

建立相应的解析器,需要打开源码对比,然后进行使用源码分析,使用BeautifulSoup获取所需信息。

为了便于主函数调用或者其他原因,将所有数据通过parser实现返回,其parser分别调用获取URL和获取数据文本的信息。

为了处理一些不同网页可能抓取的意外情况导致程序终止,添加了一些判断。

  1. import re
  2. from urllib import parse
  3. from bs4 import BeautifulSoup
  4. class HtmlParser(object):
  5. def parser(self,page_url,html_cont):
  6. if page_url is None or html_cont is None:
  7. return
  8. soup=BeautifulSoup(html_cont,'lxml')
  9. new_urls=self.getNewUrls(page_url,soup)
  10. new_data=self.getNewData(page_url,soup)
  11. return new_urls,new_data
  12.  
  13. def getNewUrls(self,page_url,soup):
  14. new_urls=set()
  15. links=soup.find_all('a',href=re.compile(r'/item/.*'))
  16. for link in links:
  17. new_url=link['href']
  18. new_full_url=parse.urljoin(page_url,new_url)
  19. new_urls.add(new_full_url)
  20. return new_urls
  21.  
  22. def getNewData(self,page_url,soup):
  23. data={}
  24. data['url']=page_url
  25. title=soup.find('dd',class_="basicInfo-item value")
  26. if title is not None:
  27. data['title']=title.string
  28. summary=soup.find('meta',attrs={"name":"description"})
  29. data['summary']=summary['content']
  30. return data
  31. else:
  32. title=soup.find('meta',attrs={"name":"keywords"})
  33. if title is not None:
  34. data['title']=title['content']
  35. summary=soup.find('meta',attrs={"name":"description"})
  36. data['summary']=summary['content']
  37. return data
  38. else:
  39. data['title']="ERROR!"
  40. data['summary']="Please check the url for more information"
  41. data['url']=page_url
  42. return data

URL管理器设计

为了避免重复的URL,使用python的set,建立集合初始化。参阅:https://www.runoob.com/python3/python3-set.html

使用old_urls存储已经访问过的网址,使用new_urls存入将要提取的网址。

然后写好has_new_url等方法,辅助主程序调用。当得到新的URL们时,主程序调用函数将他们存入。

而主程序需要的其他URL管理方案,如提取,数量判定等,也在这里实现。

  1. class UrlManager():
  2. def __init__(self):
  3. self.old_urls=set()
  4. self.new_urls=set()
  5. pass
  6.  
  7. def has_new_url(self):
  8. return self.new_url_size()!=0
  9.  
  10. def new_url_size(self):
  11. return len(self.new_urls)
  12.  
  13. def old_url_size(self):
  14. return len(self.old_urls)
  15.  
  16. def get_new_url(self):
  17. new_url=self.new_urls.pop()
  18. self.old_urls.add(new_url)
  19. return new_url
  20.  
  21. def add_new_url(self,url):
  22. if url is None:
  23. return
  24. if url not in self.new_urls and url not in self.old_urls:
  25. self.new_urls.add(url)
  26. pass
  27.  
  28. def add_new_urls(self,urls):
  29. if urls is None or len(urls) == 0:
  30. return
  31.  
  32. for url in urls:
  33. self.add_new_url(url)
  34. pass

数据存储器设计

通过HTML解析器获取的数据,通过数据存储器进行存储。

而最终将数据从内存写入到本地磁盘,也在该文件实现。

为了调试美观,建议是先爬取一两个数据做好测试,写好table的宽度设定,加入style='word-break:break-all;word-wrap:break-word;'参数。参阅:https://zhidao.baidu.com/question/1385859725784504260.html

  1. import codecs
  2. class DataOutput(object):
  3. def __init__(self):
  4. self.datas=[]
  5.  
  6. def store_data(self,data):
  7. if data is None:
  8. return
  9. self.datas.append(data)
  10.  
  11. def output_html(self):
  12. fout=codecs.open('baike.html', 'w', encoding='utf-8')
  13. fout.write("<html>")
  14. fout.write("<head><meta charset='urf-8'></head>")
  15. fout.write("<body>")
  16. fout.write("<table border='1' width=1800 style='word-break:break-all;word-wrap:break-word;'>")
  17. fout.write("<tr>")
  18. fout.write("<td width='300'>URL</td>")
  19. fout.write("<td width='100'>标题</td>")
  20. fout.write("<td width='1200'>释义</td>")
  21. fout.write("</tr>")
  22. for data in self.datas:
  23. fout.write("<tr>")
  24. fout.write("<td><a href=%s>%s</a></td>"%(data['url'],data['url']))
  25. fout.write("<td>%s</td>"%data['title'])
  26. fout.write("<td>%s</td>"%data['summary'])
  27. fout.write("</tr>")
  28. fout.write("</table>")
  29. fout.write("</body>")
  30. fout.write("</html>")
  31. fout.close()

最终效果:

当然还有一些数据没有处理好。

python网络爬虫(9)构建基础爬虫思路的更多相关文章

  1. python爬虫实战:基础爬虫(使用BeautifulSoup4等)

    以前学习写爬虫程序时候,我没有系统地学习爬虫最基本的模块框架,只是实现自己的目标而写出来的,最近学习基础的爬虫,但含有完整的结构,大型爬虫含有的基础模块,此项目也有,“麻雀虽小,五脏俱全”,只是没有考 ...

  2. 【python网络编程】新浪爬虫:关键词搜索爬取微博数据

    上学期参加了一个大数据比赛,需要抓取大量数据,于是我从新浪微博下手,本来准备使用新浪的API的,无奈新浪并没有开放关键字搜索的API,所以只能用爬虫来获取了.幸运的是,新浪提供了一个高级搜索功能,为我 ...

  3. Python学习笔记【第十三篇】:Python网络编程一Socket基础

    什么是⽹络 网络能把双方或多方连在一起的工具,即把数据从一方传递到另一方进行数据传递. 网络编程就是不同电脑上的软件能够进行数据传递.即进程间的通讯. 什么是TCP/IP协议 协议就是大家一起遵守的约 ...

  4. 6.Python网络编程_全局变量基础

    变量作用域: 一般在函数体外定义的变量成为全局变量,在函数内部定义的变量称为局部变量.全局变量所有作用域都可用,局部变量只能在本函数可用,变量的使用顺序是,局部变量 > 全局变量, 也就是说:优 ...

  5. Python36 使用Redis 构建分布式爬虫(未完)

    很长时间未更新了,人懒了. 最近有不少的东西,慢慢写吧,最近尝试了一下python 使用Redis 来构建分布式爬虫: 单体爬虫有很多缺点,但是在学习过程中能够学习爬虫的基本理念与运行模式,在后期构建 ...

  6. python代理池的构建3——爬取代理ip

    上篇博客地址:python代理池的构建2--代理ip是否可用的处理和检查 一.基础爬虫模块(Base_spider.py) #-*-coding:utf-8-*- ''' 目标: 实现可以指定不同UR ...

  7. python网络爬虫实战PDF高清完整版免费下载|百度云盘|Python基础教程免费电子书

    点击获取提取码:vg1y python网络爬虫实战帮助读者学习Python并开发出符合自己要求的网络爬虫.网络爬虫,又被称为网页蜘蛛,网络机器人,是一种按照一定的规则,自动地抓取互联网信息的程序或者脚 ...

  8. 爬虫(二)Python网络爬虫相关基础概念、爬取get请求的页面数据

    什么是爬虫 爬虫就是通过编写程序模拟浏览器上网,然后让其去互联网上抓取数据的过程. 哪些语言可以实现爬虫    1.php:可以实现爬虫.php被号称是全世界最优美的语言(当然是其自己号称的,就是王婆 ...

  9. 03.Python网络爬虫第一弹《Python网络爬虫相关基础概念》

    爬虫介绍 引入 之前在授课过程中,好多同学都问过我这样的一个问题:为什么要学习爬虫,学习爬虫能够为我们以后的发展带来那些好处?其实学习爬虫的原因和为我们以后发展带来的好处都是显而易见的,无论是从实际的 ...

随机推荐

  1. java生成10个不相等的1-20的随机数

    public class Test { public static void main(String[] args){ Random ran = new Random(); Set <Integ ...

  2. [转]java常量池理解总结

    一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. Class文件中的常量池在Clas ...

  3. thinkpad T480安装WIN7

    本文转载自http://www.dnxtc.net/zixun/zhuangjijiaocheng/2018-12-01/3256.html 防止忘记 特别把资源集中一下 新买的笔记本预装的WIN10 ...

  4. kernel hacking的一些网站

    很全面的网站,下面的网站基本都可以从该地址找到. 新手必备 subscrible/unsubscrible mail list mail list archive kernel git mainlin ...

  5. LC 553. Optimal Division

    Given a list of positive integers, the adjacent integers will perform the float division. For exampl ...

  6. LC 274. H-Index

    Given an array of citations (each citation is a non-negative integer) of a researcher, write a funct ...

  7. numpy之填充为nan的数据为该列平均值

    # coding=utf-8 import numpy as np ''' 填充nan的数据,为该列的平均值 ''' def fill_ndarray(t1): for i in range(t1.s ...

  8. (转)js控制窗口失去焦点(包括屏蔽Alt+Tab键切换页面)

    本章内容转自:http://www.cnblogs.com/BoKeYuanVinson/articles/3360954.html 转载自网络贴吧: 页面脚本是无法截获alt键的,不过可以变通一下, ...

  9. 阶段3 3.SpringMVC·_07.SSM整合案例_05.ssm整合之Spring整合SpringMVC的框架

    点击超连接,执行controller里面的方法 那么就需要在Controller里面定义Service对象,就需要依赖注入进来. 启动tomcat服务器,web.xml里面的前端控制器会帮我加载spr ...

  10. 五十九:Flask.Cookie之flask设置cookie过期时间

    设置cookie有效期1.max_age:距离现在多少秒后过期,在IE8以下不支持2.expires:datatime类型,使用此参数,需参照格林尼治时间,即北京时间-8个小时3.如果max_age和 ...