Python实现网络爬虫
进入正题,描述如何实现:
拿到一个已经有了描述的办法,实现它可以按自顶向下的思路,先将大的步骤描述出来,然后分割成小的问题,一部分一部分地解决。
对于一个网络爬虫,如果要按广度遍历的方式下载,它就是这样干活的:
1.从给定的入口网址把第一个网页下载下来
2.从第一个网页中提取出所有新的网页地址,放入下载列表中
3.按下载列表中的地址,下载所有新的网页
4.从所有新的网页中找出没有下载过的网页地址,更新下载列表
5.重复3、4两步,直到更新后的下载列表为空表时停止
其实就是简化成下面的步骤:
1.按下载列表进行下载
2.更新下载列表
3.循环操作1,2,直到列表为空结束
所以最初的设想就是写一个函数里面干这个:
def craw():
while len(urlList) != 0
Init_url_list()
Download_list()
Update_list()
当然,上面这个函数是工作不起来的,它只是最顶层的一个想法,底层的实现还没做。不过这一步很重要,至少让自己知道该干什么了。
下面的事情就是将函数每一部分实现,这个可以放在一个类里去实现,我把它命名为WebCrawler。
在python里,要按一个地址下载一个网页那并不是什么难事,你可以用urllib里的urlopen去连接上某一个网页,然后调用获取到的对象的read方法,可以得到网页的内容的字符串,像这样:
IDLE 2.6.6 ==== No Subprocess ====
>>> import urllib
>>> f = urllib.urlopen('http://www.hfut.edu.cn')
>>> s = f.read()
>>>
这样上面变量 s 里面存的就是从http://www.hfut.edu.cn这个地址里获取到的网页的内容了,是str数据类型。下面你要怎么用都可以了,把写入文件或从中提取新的地址就随你意了。当然,只要写入文件,就算下载完了这个页面。
一个爬虫程序下载的速度肯定是很重要的问题,谁也不想用一个单线程的爬虫用一次只下一个网页速度去下载,我在学校校园网,测试了单线程的爬虫,平均每秒才 下1k。所以解决的办法只有用多线程,多开几个连接同时下载就快了。本人是Python新手,东西都是临时拿来用的。
下载线程我是用了另外一个类,命名为CrawlerThread,它继承了threading.Thread这个类。
因为涉及到更新下载列表的问题,线程对某个表的读写还要考虑同步,我在代码里使用了线程锁,这个用threading.Lock()构造对象。调用对象的 acquire()和release()保证每次只有一个线程对表进行操作。当然,为了保证表的更新能够实现,我使用了多个表,一个表肯定办不成。因为你 即要知道当前要下载的网络地址,还要知道你已经下载过的网络地址。你要把已经下载过的地址从新的网页中获取到的网址列表中除去,这当中又涉及了一些临时的 表。
爬虫在下载网页的时候,最好还要把哪个网页存到了哪个文件记录好,并且记录好网页是搜索到广度搜索到的第几层的深度记录好,因为如果要做搜索引擎,这个都 是对制作索引和对网页排序有参考价值的信息。至少你自己会想知道爬虫给你下载到了什么,都放在哪了吧。对应的写记录的语句我在代码里的行末用##标注出来 了。
写的文字已经很多了,不想再写了,直接贴上代码:
文件Test.py内容如下:(它调用了WebCrawler,运行时是运行它)
--------------------------------------------------------
# -*- coding: cp936 -*-
import WebCrawler
url = raw_input('设置入口url(例-->http://www.baidu.com): \n')
thNumber = int(raw_input('设置线程数:')) #之前类型未转换出bug
wc = WebCrawler.WebCrawler(thNumber)
wc.Craw(url)
文件WebCrawler.py内容如下:
--------------------------------------------------------
# -*- coding: cp936 -*-
import threading
import GetUrl
import urllib
g_mutex = threading.Lock()
g_pages = [] #线程下载页面后,将页面内容添加到这个list中
g_dledUrl = [] #所有下载过的url
g_toDlUrl = [] #当前要下载的url
g_failedUrl = [] #下载失败的url
g_totalcount = 0 #下载过的页面数
class WebCrawler:
def __init__(self,threadNumber):
self.threadNumber = threadNumber
self.threadPool = []
self.logfile = file('#log.txt','w') ##
def download(self, url, fileName):
Cth = CrawlerThread(url, fileName)
self.threadPool.append(Cth)
Cth.start()
def downloadAll(self):
global g_toDlUrl
global g_totalcount
i = 0
while i < len(g_toDlUrl):
j = 0
while j < self.threadNumber and i + j < len(g_toDlUrl):
g_totalcount += 1 #进入循环则下载页面数加1
self.download(g_toDlUrl[i+j],str(g_totalcount)+'.htm')
print 'Thread started:',i+j,'--File number = ',g_totalcount
j += 1
i += j
for th in self.threadPool:
th.join(30) #等待线程结束,30秒超时
self.threadPool = [] #清空线程池
g_toDlUrl = [] #清空列表
def updateToDl(self):
global g_toDlUrl
global g_dledUrl
newUrlList = []
for s in g_pages:
newUrlList += GetUrl.GetUrl(s) #######GetUrl要具体实现
g_toDlUrl = list(set(newUrlList) - set(g_dledUrl)) #提示unhashable
def Craw(self,entryUrl): #这是一个深度搜索,到g_toDlUrl为空时结束
g_toDlUrl.append(entryUrl)
depth = 0
while len(g_toDlUrl) != 0:
depth += 1
print 'Searching depth ',depth,'...\n\n'
self.downloadAll()
self.updateToDl()
content = '\n>>>Depth ' + str(depth)+':\n' ##(该标记表示此语句用于写文件记录)
self.logfile.write(content) ##
i = 0 ##
while i < len(g_toDlUrl): ##
content = str(g_totalcount + i) + '->' + g_toDlUrl[i] + '\n' ##
self.logfile.write(content) ##
i += 1 ##
class CrawlerThread(threading.Thread):
def __init__(self, url, fileName):
threading.Thread.__init__(self)
self.url = url #本线程下载的url
self.fileName = fileName
def run(self): #线程工作-->下载html页面
global g_mutex
global g_failedUrl
global g_dledUrl
try:
f = urllib.urlopen(self.url)
s = f.read()
fout = file(self.fileName, 'w')
fout.write(s)
fout.close()
except:
g_mutex.acquire() #线程锁-->锁上
g_dledUrl.append(self.url)
g_failedUrl.append(self.url)
g_mutex.release() #线程锁-->释放
print 'Failed downloading and saving',self.url
return None #记着返回!
g_mutex.acquire() #线程锁-->锁上
g_pages.append(s)
g_dledUrl.append(self.url)
g_mutex.release() #线程锁-->释放
文件GetUrl.py内容如下:(它里面的GetUrl从一个存有网页内容的字符串中获取所有url并以一个list返回,这部分实现方法很多,大家可以自己写个更好的)
--------------------------------------------------------
urlSep = ['<','>','\\','(',')', r'"', ' ', '\t', '\n']
urlTag = ['http://']
def is_sep(ch):
for c in urlSep:
if c == ch:
return True
return False
def find_first_sep(i,s):
while i < len(s):
if is_sep(s[i]):
return i
i+=1
return len(s)
def GetUrl(strPage):
rtList = []
for tag in urlTag:
i = 0
i = strPage.find(tag, i, len(strPage))
while i != -1:
begin = i
end = find_first_sep(begin+len(tag),strPage)
rtList.append(strPage[begin:end])
i = strPage.find(tag, end, len(strPage))
return rtList
转载于:https://my.oschina.net/u/240562/blog/51592
Python实现网络爬虫相关推荐
- Python3网络爬虫快速入门实战解析(一小时入门 Python 3 网络爬虫)
Python3网络爬虫快速入门实战解析(一小时入门 Python 3 网络爬虫) https://blog.csdn.net/u012662731/article/details/78537432 出 ...
- 网页爬虫python代码_《用python写网络爬虫》完整版+源码
原标题:<用python写网络爬虫>完整版+源码 <用python写网络爬虫>完整版+附书源码 本书讲解了如何使用Python来编写网络爬虫程序,内容包括网络爬虫简介,从页面中 ...
- Python学习网络爬虫--转
原文地址:https://github.com/lining0806/PythonSpiderNotes Python学习网络爬虫主要分3个大的版块:抓取,分析,存储 另外,比较常用的爬虫框架Scra ...
- Python即时网络爬虫项目: 内容提取器的定义(Python2.7版本)
1. 项目背景 在Python即时网络爬虫项目启动说明中我们讨论一个数字:程序员浪费在调测内容提取规则上的时间太多了(见上图),从而我们发起了这个项目,把程序员从繁琐的调测规则中解放出来,投入到更高端 ...
- 《用Python写网络爬虫》——1.5 本章小结
本节书摘来自异步社区<用Python写网络爬虫>一书中的第1章,第1.5节,作者 [澳]Richard Lawson(理查德 劳森),李斌 译,更多章节内容可以访问云栖社区"异步 ...
- Python之父推荐!《Python 3网络爬虫开发实战》第二版!文末送签名版!
很多读者会让我写爬虫方面的书籍,我也一直没写,没写的原因主要有两个,第一个就是在爬虫方面我其实不是很擅长,第二个原因就是因为在爬虫领域庆才已经做的足够好了,我写不一定能写出庆才这水平的,所以也就一直没 ...
- 用Python写网络爬虫pdf
下载地址:网盘下载 作为一种便捷地收集网上信息并从中抽取出可用信息的方式,网络爬虫技术变得越来越有用.使用Python这样的简单编程语言,你可以使用少量编程技能就可以爬取复杂的网站. <用Pyt ...
- python网络爬虫_python小知识,基于Python 的网络爬虫技术分析
在现阶段大数据的时代中,想要实现对数据的获取和分析,要先具备足够的数据源,网络爬虫技术就为其数据获取提供了良好的条件,且还能够实现对数据源的目的性采集. 在网络爬虫技术应用中,Python 脚本语言的 ...
- 爬虫技术python流程图_基于Python的网络爬虫技术研究
基于 Python 的网络爬虫技术研究 王碧瑶 [摘 要] 摘要:专用型的网络爬虫能够得到想要的返回结果 , 本文就以拉勾网作 为例子 , 对基于 Python 的网络爬虫技术进行研究和分析. [期刊 ...
- 用python写网络爬虫 第2版 pd_用Python写网络爬虫(第2版)
用Python写网络爬虫(第2版)电子书 畅销的Python网络爬虫发实战图书全新升级版,上一版年销量近40000册. 针对Python 3.6版本编写. 提供示例完整源码和实例网站搭建源码,确保用户 ...
最新文章
- R语言data.table进行滚动数据连接,滚动联接通常用于分析涉及时间的数据实战(动画说明滚动数据连接的形式):rolling joins data.table in R
- vue前端上传文件夹的插件_基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件...
- php基础教程 第一步 环境配置及helloworld
- QT 提示之右下角冒泡
- java mockserver搭建_mockjs,json-server一起搭建前端通用的数据模拟框架教程
- 《从问题到程序:用Python学编程和计算》——2.6 简单脚本程序
- leetcode题库1277-- 统计全为 1 的正方形子矩阵
- 关于陀螺仪 deviceorientation
- 用linux制作Mac OS U盘启动
- 模2除法与二进制除法
- js传递参数时类型错误
- 【Lintcode】350. Slash Separating
- programming paradigm
- glib安装详细教程
- win10查看显卡的运算能力
- CSC公派|高职院校教师赴澳大利亚大学访学
- 2014全国计算机等级考试大纲,2014全国计算机等级考试大纲级.doc
- VUE动态切换Button的icon
- STM32通过PWM驱动两个直流电机
- Win11 + wsl2 + xfce4实现可视化ubuntu的问题