1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 【Python爬虫】Python网络爬虫案例:维基百科

【Python爬虫】Python网络爬虫案例:维基百科

时间:2022-06-05 17:49:44

相关推荐

【Python爬虫】Python网络爬虫案例:维基百科

Python网络爬虫案例:维基百科

1.项目描述

本案例的目标是爬取维基百科上的词条连接。爬虫深度设置为两层。

网络蜘蛛:是通过网页的链接地址寻找网页的,从网站某一个页面(通常是首页)开始读取网页的内容,找到在网页中其他链接地址,然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止。

如何把整个网站的所有网页都爬取一遍呢?涉及到两个基本算法:基于深度优先的遍历和基于广度优先的遍历。

2.网站分析

网页首页为:/wiki/Wikipedia

首先,分析词条链接的特点;

然后,得到该页面的所有链接:

#!/usr/bin/env python# -*- coding: utf-8 -*-"""@File : GetLink.py@Author: Xinzhe.Pang@Date : /7/18 20:44@Desc : """import requestsfrom bs4 import BeautifulSoupurl = "/wiki/Wikipedia"headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}r = requests.get(url, headers=headers)html = r.textbsObj = BeautifulSoup(html)for link in bsObj.find_all("a"):if 'href' in link.attrs:print(link.attrs['href'])

通过分析,可以发现所有词条的链接有两个特点:

(1)URL链接是以/wiki/开头的相对路径;

(2)URL链接不包括冒号、#、=、<、>。

这里,直接用正则表达式从网页HTML代码中提取需要的词条链接,正则表达式为<a href="/wiki/([^:#=<>]*?)".*?</a>。

3.深度优先的递归爬虫

#!/usr/bin/env python# -*- coding: utf-8 -*-"""@File : DeepFirst.py@Author: Xinzhe.Pang@Date : /7/18 21:13@Desc : """import requestsimport reexist_url = [] # 存放已爬取的网页g_writecount = 0def scrappy(url, depth=1):global g_writecounttry:headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}url = "/wiki/" + urlr = requests.get(url, headers=headers)html = r.textexcept Exception as e:print('Failed downloading and saving', url)print(e)exist_url.append(url)return Noneexist_url.append(url)link_list = re.findall('<a href="/wiki/([^:#=<>]*?)".*?</a>', html)# 去掉已爬链接和重复链接unique_list = list(set(link_list) - set(exist_url))# 把所有链接写出到txt文件for eachone in unique_list:g_writecount += 1output = "No." + str(g_writecount) + "\t Depth:" + str(depth) + "\t" + url + ' -> ' + eachone + '\n'print(output)with open('link_12-3.txt', "a+") as f:f.write(output)# 只获取两层,"Wikipedia"算第一层if depth < 2:# 递归调用自己来访问下一层scrappy(eachone, depth + 1)scrappy("Wikipedia")

每一个新获取的链接都有要先保存到TXT文件中,再使用递归函数调用。

4.广度优先的多线程爬虫

多线程爬虫配合广度优先算法正好。广度优先的遍历算法以层为顺序,将某一层上的所有节点都搜索到了之后才向下一层搜索,可以有大量词条链接放入多线程爬虫的队列中。

#!/usr/bin/env python# -*- coding: utf-8 -*-"""@File : BreadthFirst.py@Author: Xinzhe.Pang@Date : /7/18 21:34@Desc : """import reimport timeimport threadingimport requestsg_mutex = threading.Condition()g_pages = [] # 从中解析所有urll链接g_queueURL = [] # 等待爬取的url链接列表g_existURL = [] # 已经爬取过的url链接列表g_writecount = [] # 找到的链接数class Crawler:def __init__(self, url, threadnum):self.url = urlself.threadnum = threadnumself.threadpool = []# 爬虫的控制大脑,包括爬取网页,更新队列def craw(self):global g_queueURLg_queueURL.append(url)depth = 1while (depth < 3):print('Searching depth ', depth, '...\n')self.downloadAll()self.updateQueueURL()g_pages = []depth += 1# 调用多线程爬虫,在小于线程最大值和没爬完队列之前会增加线程def downloadAll(self):global g_queueURLi = 0while i < len(g_queueURL):j = 0while j < self.threadnum and i + j < len(g_queueURL):threadresult = self.download(g_queueURL[i + j], j)j += 1i += jfor thread in self.threadpool:thread.join(30)threadpool = []g_queueURL = []# 调用多线程爬虫def download(self, url, tid):crawthread = CrawlerThread(url, tid)self.threadpool.append(crawthread)crawthread.start()# 完成一个深度的爬虫之后更新队列def updateQueueURL(self):global g_queueURLglobal g_existURLnewUrlList = []for content in g_pages:newUrlList += self.getUrl(content)g_queueURL = list(set(newUrlList) - set(g_existURL))# 从获取的网页中解析urldef getUrl(self, content):link_list = re.findall('<a href="/wiki/([^:#=<>]*?)".*?</a>', content)unique_list = list(set(link_list))return unique_list# 爬虫线程class CrawlerThread(threading.Thread):def __init__(self, url, tid):threading.Thread.__init__(self)self.url = urlself.tid = tiddef run(self):global g_mutexglobal g_writecounttry:print(self.tid, "crawl ", self.url)headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}r = requests.get("/wiki/" + self.url, headers=headers)html = r.textlink_list2 = re.findall('<a href="/wiki/([^:#=<>]*?)".*?</a>', html)unique_list2 = list(set(link_list2))for eachone in unique_list2:g_writecount += 1content2 = "No." + str(g_writecount) + "\t Thread:" + str(self.tid) + "\t" + self.url + ' -> ' + eachone + '\n'with open('title2.txt', "a+") as f:f.write(content2)f.close()except Exception as e:g_mutex.acquire()g_existURL.append(self.url)g_mutex.release()print('Failed downloading and saving', self.url)print(e)return Noneg_mutex.acquire()g_pages.append(html)g_existURL.append(self.url)g_mutex.release()if __name__ == "__main__":url = "Wikipedia"threadnum = 5crawler = Crawler(url, threadnum)crawler.craw()

补充说明:由于网络问题,无法登录/wiki/Wikipedia,所以,上述代码仅供学习参考。如果有条件,可以考虑翻墙之后再行实验。

参考资料:《Python网络爬虫从入门到实践》

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。