Python网络爬虫原理及实例教程

本人刚学Python不久,前段时间看到华南师范大学有一个网络爬虫的项目,特意研究了一下,用Python写了一个可以多线程下载的网络爬虫。

网络爬虫基本原理

网络爬虫是?人饕?孀ト∠低车闹匾?槌刹糠帧E莱娴闹饕?康氖墙?チ??系耐?诚略氐奖镜匦纬梢桓龌蛄??谌莸木迪癖阜荨U馄?┛椭饕?耘莱嬉约白ト∠低辰?幸桓黾虻サ母攀觥?/p>

一、网络爬虫的基本结构及工作流程

一个通用的网络爬虫的框架如图所示:

 

网络爬虫的基本工作流程如下:

1.首先选取一部分精心挑选的种子URL;

2.将这些URL放入待抓取URL队列;

3.从待抓取URL队列中取出待抓取在URL,解析DNS,并且得到主机的ip,并将URL对应的网页下载下来,存储进已下载网页库中。此外,将这些URL放进已抓取URL队列。

4.分析已抓取URL队列中的URL,分析其中的其他URL,并且将URL放入待抓取URL队列,从而进入下一个循环。

二、从爬虫的角度对互联网进行划分

对应的,可以将互联网的所有页面分为五个部分:

 

1.已下载未过期网页

2.已下载已过期网页:抓取到的网页实际上是互联网内容的一个镜像与备份,互联网是动态变化的,一部分互联网上的内容已经发生了变化,这时,这部分抓取到的网页就已经过期了。

3.待下载网页:也就是待抓取URL队列中的那些页面

4.可知网页:还没有抓取下来,也没有在待抓取URL队列中,但是可以通过对已抓取页面或者待抓取URL对应页面进行分析获取到的URL,认为是可知网页。

5.还有一部分网页,爬虫是无法直接抓取下载的。称为不可知网页。

三、抓取策略

在爬虫系统中,待抓取URL队列是很重要的一部分。待抓取URL队列中的URL以什么样的顺序排列也是一个很重要的问题,因为这涉及到先抓取那个页面,后抓取哪个页面。而决定这些URL排列顺序的方法,叫做抓取策略。下面重点介绍几种常见的抓取策略:

1.深度优先遍历策略

深度优先遍历策略是指网络爬虫会从起始页开始,一个链接一个链接跟踪下去,处理完这条线路之后再转入下一个起始页,继续跟踪链接。我们以下面的图为例:

 

遍历的路径:A-F-G E-H-I B C D

2.宽度优先遍历策略

宽度优先遍历策略的基本思路是,将新下载网页中发现的链接直接插入待抓取URL队列的末尾。也就是指网络爬虫会先抓取起始网页中链接的所有网页,然后再选择其中的一个链接网页,继续抓取在此网页中链接的所有网页。还是以上面的图为例:

遍历路径:A-B-C-D-E-F G H I

3.反向链接数策略

反向链接数是指一个网页被其他网页链接指向的数量。反向链接数表示的是一个网页的内容受到其他人的推荐的程度。因此,很多时候搜索引擎的抓取系统会使用这个指标来评价网页的重要程度,从而决定不同网页的抓取先后顺序。

在真实的网络环境中,由于广告链接、作弊链接的存在,反向链接数不能完全等他我那个也的重要程度。因此,搜索引擎往往考虑一些可靠的反向链接数。

4.Partial PageRank策略

Partial PageRank算法借鉴了PageRank算法的思想:对于已经下载的网页,连同待抓取URL队列中的URL,形成网页集合,计算每个页面的 PageRank值,计算完之后,将待抓取URL队列中的URL按照PageRank值的大小排列,并按照该顺序抓取页面。

如果每次抓取一个页面,就重新计算PageRank值,一种折中方案是:每抓取K个页面后,重新计算一次PageRank值。但是这种情况还会有一个问题:对于已经下载下来的页面中分析出的链接,也就是我们之前提到的未知网页那一部分,暂时是没有PageRank值的。为了解决这个问题,会给这些页面一个临时的PageRank值:将这个网页所有入链传递进来的PageRank值进行汇总,这样就形成了该未知页面的PageRank值,从而参与排序。下面举例说明:

5.OPIC策略策略

该算法实际上也是对页面进行一个重要性打分。在算法开始前,给所有页面一个相同的初始现金(cash)。当下载了某个页面P之后,将P的现金分摊给所有从P中分析出的链接,并且将P的现金清空。对于待抓取URL队列中的所有页面按照现金数进行排序。

6.大站优先策略

对于待抓取URL队列中的所有网页,根据所属的网站进行分类。对于待下载页面数多的网站,优先下载。这个策略也因此叫做大站优先策略。

我使用的网络爬虫下载网页的算法是广度搜索(BFS),网络上对爬虫实现算法的评价中,广度搜索的算法是排行第二的,最好的算法是按网页重要性排序后再确定下载顺序(这个算法很灵活,怎么排序本人不是很了解)。

进入正题,描述如何实现:
拿到一个已经有了描述的办法,实现它可以按自顶向下的思路,先将大的步骤描述出来,然后分割成小的问题,一部分一部分地解决。
对于一个网络爬虫,如果要按广度遍历的方式下载,它就是这样干活的:
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,'...nn'
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))

 

时间: 2024-10-01 13:32:54

Python网络爬虫原理及实例教程的相关文章

【Python爬虫9】Python网络爬虫实例实战

爬Google搜索引擎 爬Facebook和Linkein 1自动化登录Facebook 2提取Facebook的API数据 3自动化登录Linkedin 爬在线商店Gap 爬宝马官网 爬取Google真实的搜索表单 爬取依赖JavaScript的网站Facebook 爬取典型在线商店Gap 爬取拥有地图接口的宝马官网 1.爬Google搜索引擎 # -*- coding: utf-8 -*- import sys import urllib import urlparse import lxm

精通Python网络爬虫:核心技术、框架与项目实战.3.1 网络爬虫实现原理详解

 摘要 通过前面章节的学习,我们已经基本认识了网络爬虫,那么网络爬虫应该怎么实现?核心技术又有哪些呢?在本篇中,我们首先会介绍网络爬虫的相关实现原理与实现技术:随后,讲解Urllib库的相关实战内容:紧接着,带领大家一起开发几种典型的网络爬虫,让大家在实战项目中由浅入深地掌握Python网络爬虫的开发:在学会了一些经典的网络爬虫开发之后,我们将一起研究学习Fiddler抓包分析技术.浏览器伪装技术.爬虫定向抓取技术等知识,让大家更加深入地进入到网络爬虫技术的世界中来.   第3章 网络爬虫实现原

精通Python网络爬虫:核心技术、框架与项目实战导读

前 言 为什么写这本书 网络爬虫其实很早就出现了,最开始网络爬虫主要应用在各种搜索引擎中.在搜索引擎中,主要使用通用网络爬虫对网页进行爬取及存储. 随着大数据时代的到来,我们经常需要在海量数据的互联网环境中搜集一些特定的数据并对其进行分析,我们可以使用网络爬虫对这些特定的数据进行爬取,并对一些无关的数据进行过滤,将目标数据筛选出来.对特定的数据进行爬取的爬虫,我们将其称为聚焦网络爬虫.在大数据时代,聚焦网络爬虫的应用需求越来越大. 目前在国内Python网络爬虫的书籍基本上都是从国外引进翻译的,

精通Python网络爬虫(0):网络爬虫学习路线

作者:韦玮 转载请注明出处 随着大数据时代的到来,人们对数据资源的需求越来越多,而爬虫是一种很好的自动采集数据的手段. 那么,如何才能精通Python网络爬虫呢?学习Python网络爬虫的路线应该如何进行呢?在此为大家具体进行介绍. 1.选择一款合适的编程语言 事实上,Python.PHP.JAVA等常见的语言都可以用于编写网络爬虫,你首先需要选择一款合适的编程语言,这些编程语言各有优势,可以根据习惯进行选择.在此笔者推荐使用Python进行爬虫项目的编写,其优点是:简洁.掌握难度低. 2.掌握

Python实现命令行通讯录实例教程_python

1.实现目标 编写一个命令行通讯录程序,可以添加.查询.删除通讯录好友及电话 2.实现方法 创建一个类来表示一个人的信息.使用字典存储每个人的对象,名字作为键. 使用pickle模块永久地把这些对象存储下来. 使用字典内建的方法添加.删除修改人员信息. 3.思维导图 4.编写伪代码 # 1.创建字典用来存储通讯录信息 # 2.创建人员类,包含姓名.关系.电话三个属性 # 3.创建操作类,包含增加.查询.删除人员,退出,保存并退出五个方法 # 4.程序运行 # 5.判断通讯录文件是否存在 # 6.

精通Python网络爬虫:核心技术、框架与项目实战.3.7 实例——metaseeker

3.7 实例--metaseeker metaseeker是一款比较实用的网站数据采集程序,使用该采集程序,可以让大家比较快速.形象地了解爬虫的工作过程.所以在本节中,会以metaseeker为例,跟大家一起学习如何采集当当网的商品及价格信息,让大家对爬虫工作过程有一个形象地了解,为后续我们使用Python开发爬虫打下基础. 如图3-5所示,我们将为大家爬取当当网新书栏目下的商品的名称及价格等信息(http://e.dangdang.com/morelist_page.html?columnTy

Python网络爬虫反爬破解策略实战

​​作者:韦玮 转载请注明出处 我们经常会写一 些网络爬虫,想必大家都会有一个感受,写爬虫虽然不难,但是反爬处理却很难,因为现在大部分的网站都有自己的反爬机制,所以我们要爬取这些数据会比较难.但是,每一种反爬机制其实我们都会有相应的解决方案,作为爬虫方的我们,重点需要处理这些反爬机制,所以,今天我们在这里就为大家分析常见的反爬策略以及破解的手段. 1. 知己知彼-常见的反爬策略有哪些? 首先,既然要破解这些常见的反爬策略,就首先需要知道常见的反爬策略有哪些,所谓知己知彼,百战百胜. 常见的反爬策

精通Python网络爬虫:核心技术、框架与项目实战.1.1 初识网络爬虫

摘要 网络爬虫也叫做网络机器人,可以代替人们自动地在互联网中进行数据信息的采集与整理.在大数据时代,信息的采集是一项重要的工作,如果单纯靠人力进行信息采集,不仅低效繁琐,搜集的成本也会提高.此时,我们可以使用网络爬虫对数据信息进行自动采集,比如应用于搜索引擎中对站点进行爬取收录,应用于数据分析与挖掘中对数据进行采集,应用于金融分析中对金融数据进行采集,除此之外,还可以将网络爬虫应用于舆情监测与分析.目标客户数据的收集等各个领域.当然,要学习网络爬虫开发,首先需要认识网络爬虫,在本篇中,我们将带领

精通Python网络爬虫:核心技术、框架与项目实战.1.6 小结

1.6 小结 1)网络爬虫也叫作网络蜘蛛.网络蚂蚁.网络机器人等,可以自动地浏览网络中的信息,当然浏览信息的时候需要按照我们制定的规则去浏览,这些规则我们将其称为网络爬虫算法.使用Python可以很方便地编写出爬虫程序,进行互联网信息的自动化检索. 2)学习爬虫,可以:①私人订制一个搜索引擎,并且可以对搜索引擎的数据采集工作原理,进行更深层次地理解:②为大数据分析提供更多高质量的数据源:③更好地研究搜索引擎优化:④解决就业或跳槽的问题. 3)网络爬虫由控制节点.爬虫节点.资源库构成. 4)网络爬