爬虫总调度程序:
#-*-coding:UTF-8 -*- from Html_Download import HtmlDownload #从Html_Download.py文件中导入HtmlDownload类,以下相同 from Url_Manage import UrlManage from Html_Parse import HtmlParse from Output_Data import OutputData class NBASpiderMain(): #定义一个NBASpiderMain()类 def __init__(self): #个人理解对类进行初始化。关于更多__init__的理解详见:http://www.crifan.com/summary_the_meaning_of_self_and___init___in_python_and_why_need_them/ self.urls = UrlManage() #创建urls,download,parser,oupter对象。分别对应爬虫框架的 self.downloader = HtmlDownload() #url管理器,下载器,解析器,和对文件的输出 self.parser = HtmlParse() self.outputer = OutputData() def craw(self,root_url): #定义一个爬取的方法 self.urls.addUrl(root_url) #将原始URL通过urls的addUrl方法添加到待爬取的URL池中 while self.urls.hasUrl(): #urls对象调用hasUrl方法,判断URL池中是否含有待爬取的URL url = self.urls.getUrl() #如果存在待爬取的URL,通过urls的getUrl方法获取一个待爬取URL html_count = self.downloader.getHtmlCount(url) #通过调用下载器的getHtmlCount()方法去获取网页源码 playerUrls = self.parser.getPlayerUrls(html_count) #通过解析,得到第二层待爬取的URL(球员信息所在的页面)。返回一个列表 while playerUrls: #爬取后的得到的列表中的URL不为空 playerUrl = playerUrls.pop() #pop()方法,得到一个列表中元素,同时在列表中删除这个元素。(拿出来不放回去) self.urls.addPlayerUrl(playerUrl) #将以爬取的球员信息URL存储在一个列表中 HtmlPlayer = self.downloader.getHtmlCount(playerUrl) #爬取球员信息URL,得其源码 PlayerData = self.parser.getPlayerData(HtmlPlayer) #解析源码,得球员信息 self.outputer.writeData(PlayerData) #将球员信息写入文件 print(playerUrl+"数据爬取完成") if __name__ == "__main__": root_url = "http://nba.sports.sina.com.cn/players.php?dpc=1" obj_spider = NBASpiderMain() #创建一个爬取NBA数据的对象 obj_spider.craw(root_url) #调用对象的爬取方法 url管理器: #-*-coding:UTF-8 -*- class UrlManage(object): ''' URL管理器,管理URL池''' def __init__(self): #初始化此类 self.new_url=set() #创建一个new_url集合,用来存储待爬取得URL #self.player_url = set() self.old_player_url = set() #创建一个已经爬取的球员信息URL def hasUrl(self): #创建判断待爬取的列表中是否存在URL if self.new_url: #如果待爬取的列表不为空 return True else: False def addUrl(self,url): #增加待爬取的URL到列表中 if url not in self.new_url: self.new_url.add(url) else: return "该url已经爬取过" def getUrl(self): #获取待爬取的URL中的一个URL元素 if self.new_url: return self.new_url.pop() else: return "已经没有可爬取的URL" def addPlayerUrl(self,url): #增加一个已经爬取的球员信息URL到列表中 self.old_player_url.add(url) return 下载器: #-*-coding:UTF-8 -*- import requests class HtmlDownload(object): """docstring for HtmlDownload""" def getHtmlCount(self,url): try: r = requests.get(url) r.raise_for_status() r.encoding = r.apparent_encoding return r.text except Exception as e : print(e) print("下载网页源码失败") 解析器: #-*-coding:UTF-8-*- import re from bs4 import BeautifulSoup class HtmlParse(object): """docstring for HtmlParse用于解析HTML来得到球员信息的类""" def __init__(self): #初始化解析器 self.playerUrl=set() self.HtmlData = [] def getPlayerUrls(self,html_count): #解析原始页面中各个球员信息的URL,返回一个集合 soup = BeautifulSoup(html_count,"html.parser") playerUrlsPart = soup.find_all('a') for url in playerUrlsPart: path = re.findall(r'a href="player\.php?(.+)">.*</a>',str(url)) if path: self.playerUrl.add("http://nba.sports.sina.com.cn/player.php"+"".join(i for i in path)) print("http://nba.sports.sina.com.cn/player.php"+"".join(i for i in path)) else: continue return self.playerUrl def getPlayerName(self,html_count): #由于BeautifulSoup没有解析出名字,使用之前的正则表达式解析 player_name = re.findall(r'<strong style="font-size:14px;">(.+)</strong>',html_count) return player_name def getPlayerTeam(self,html_count): #由于BeautifulSoup没有解析出球队名字,使用之前的正则表达式解析 team_name = re.findall(r'<a href="http://nba\.sports\.sina\.com\.cn/team/.+\.shtml" target="_blank">(.+)</a>',html_count) return team_name[0] #解析出该球员每个赛季虽所在的球队名字,选取第一个就是今年现在所在的 def getPlayerData(self,html_count): #通过BeautifulSoup解析球员信息。解析出为下面注释的列表内容,通过索引得到想要的信息 soup = BeautifulSoup(html_count,"html.parser") player_data = {} #通过字典来存储球员信息的对象 tr = soup.find_all(bgcolor=re.compile(r'#fcac08')) #find_all()方法加正则来寻找球员信息所在的<tr>标签。加入正则目的是过滤掉其他<tr>的内容 for i in tr: #返回的是列表,所以遍历 for x in i.find_all('td'): #对每个<tr>标签,向下寻找子标签<td>,返回还是列表,所以遍历 self.HtmlData.append(x.string) #返回每个<td>标签的String内容,并添加到一个列表中 player_data["name"] = self.getPlayerName(html_count) player_data["team_name"] = self.getPlayerTeam(html_count) player_data["age"] = self.HtmlData[4] player_data["birthday"] = self.HtmlData[2] player_data["height"] = self.HtmlData[10] player_data["weight"] = self.HtmlData[12] player_data["veteran"] = self.HtmlData[-7] return player_data ''' 从网页上通过BeautifulSoup上解析出来的数据,保存在列表中 [None, '生\u3000\u3000日', '1984-03-24', '年\u3000\u3000龄', '33岁', '出 生 地', '德克萨斯州达拉斯', '毕业学校', 'Georgi a Tech', '身\u3000\u3000高', '\r\n\t2.11米(6英尺11英寸)\r\n\t', '体\u3000\u3000重', '\r\n\t107公斤(235磅)', '进入 NBA', '2003年', 'NBA 球龄', '13年', '伤病情况', None, '停赛情况', None, '选秀情况', '\r\n\t2003年第1轮第4顺位被猛龙队选中'] ''' ''' 一下代码为当初分析时使用的正则,当爬取到体重身高数据时不会爬取了,改用BeautifulSoup网页解析 def getPlayerData_2(self,html_count): player_data = {} player_data["name"] = self.getPlayerName(html_count) player_data["age"] = self.getPlayerAge(html_count) player_data["birthday"] = self.getPlayerBirthday(html_count) player_data["height"] = self.getPlayerHeigth(html_count) player_data["weight"] = self.getPlayerWeight(html_count) player["veteran"] = self.getPlayerVeteran(html_count) return player_data def getPlayerName(self,html_count,soup): player_name = re.findall(r'<strong style="font-size:14px;">(.+)</strong>',html_count) return player_name def getPlayerTeam(self,html_count): team_name = re.findall(r'<a href="http://nba\.sports\.sina\.com\.cn/team/.+\.shtml" target="_blank">(.+)</a>',html_count) return TeamName def getPlayerAge(self,html_count): player_age = re.findall(r'<td width=197>(.*)</td>',html_count)[1] return player_age def getPlayerBirthday(self,html_count): player_birthday = re.findall(r'<td width=197>(.*)</td>',r.text)[0] return player_birthday def getPlayerHeigth(self,html_count): p def getPlayerWeight(self,html_count): pass def getPlayerVeteran(self,html_count): pass ''' 输出数据: #-*-encoding:UTF-8 -*- import os class OutputData(object): def __int__(self): self.path = r"D:\\NBAPlayerData" def writeData(self,player_data): self.path = r"D:\\NBAPlayerData" if os._exists(self.path): f = open(path+".txt","a") data = str(player_data["name"])+" "+str(player_data["team_name"])+" "+str(player_data["age"])+" "+str(player_data["birthday"])+" "+str(player_data["height"])+" "+str(player_data["weight"])+" "+str(player_data["veteran"]) f.write(data) f.close() 以上为全部代码,欢迎指出错误。(关于函数的访问控制在此没有涉及,这是个毛病)
