本文主要介紹使用Python爬蟲爬取Python百度詞條的信息 主要參考慕課網(wǎng)的《開發(fā)簡(jiǎn)單爬蟲》以及一些數(shù)據(jù)庫操作
開發(fā)工具
---工欲善其事 必先利其器
首先 這里開發(fā)工具用的Python3.6+Pycharm+MySQL5.7+SQLyog
前面2個(gè)的安裝直接網(wǎng)上搜下教程一大堆 而且免去了配置環(huán)境變量的操作,MySQL數(shù)據(jù)庫(安裝教程也一大堆)現(xiàn)在最新版是5.7 它的安裝與之前的有點(diǎn)不同
注意到?jīng)] 安裝時(shí)多了一個(gè)必須選項(xiàng) 安裝InnoDB時(shí)設(shè)置password 然后再填入即可 其它步驟和一般軟件沒什么區(qū)別
然后去搜索引擎下載SQLyog工具(用Pycharm自帶的dataBase應(yīng)該也可以 有興趣的小伙伴可以去試試 ) 連接數(shù)據(jù)庫
點(diǎn)擊連接 出錯(cuò)的可以看看 進(jìn)入控制面板→管理工具→服務(wù)→看MySQL service是否打開 連接好后創(chuàng)建數(shù)據(jù)庫baikeurl 然后建url表
爬蟲的架構(gòu)及具體流程
1.傳入目標(biāo)url后調(diào)用URL管理器
2.URL管理器對(duì)URL進(jìn)行具體的判斷與檢索后傳入網(wǎng)頁下載器
3.網(wǎng)頁下載器工作后將網(wǎng)頁傳入網(wǎng)頁解析器
4.將解析后的內(nèi)容(url拓瞪,title,content等)傳入輸出器
5.最后輸出器進(jìn)行數(shù)據(jù)操作(寫入文件 導(dǎo)入數(shù)據(jù)庫等)
整個(gè)過程采用了嚴(yán)格的面向?qū)ο笏枷?每一過程具體的函數(shù)都封裝在相應(yīng)文件中
實(shí)例分析
要爬取的鏈接:http://baike.baidu.com/item/Python
通過瀏覽器的開發(fā)者工具分析可知 百度百科的詞條
鏈接:/item/……的形式
標(biāo)題: <dd class="lemmaWgt-lemmaTitle-title"><h1>……</h1> 內(nèi)容:<div class="lemma-summary">……</div>
廢話不多說 直接上代碼 關(guān)鍵地方帶注釋 一個(gè)包括5個(gè)文件
爬蟲調(diào)度端(主頁)
spider.py文件
import html_downloader
import html_outputer
import html_parser
import url_manager
#爬蟲主函數(shù)
class SpiderMain(object):
def __init__(self):
self.urls = url_manager.UrlManager()
self.downloader = html_downloader.HtmlDownloader()
self.parser = html_parser.HtmlParser()
self.outputer = html_outputer.HtmlOutputer()
#抓取過程函數(shù)
def craw(self, root_url):
count = 1
self.urls.add_new_url(root_url)
while self.urls.has_new_url():
try:
new_url = self.urls.get_new_url()
print('craw %d : %s' % (count, new_url))
html_cont = self.downloader.download(new_url)
new_urls, new_data = self.parser.parse(new_url, html_cont)
self.urls.add_new_urls(new_urls)
self.outputer.collect_data(new_data)
if count == 1000:
break
count = count+1
except:
print('craw failed')
self.outputer.into_mysql()
if __name__ == '__main__':
rooturl = 'http://baike.baidu.com/item/Python'
obj_spider = SpiderMain()
obj_spider.craw(rooturl)
url管理器
url_manager.py文件
# -*- coding: utf-8 -*-
class UrlManager(object):
def __init__(self):
self.new_urls = set()
self.old_urls = set()
def add_new_url(self, root_url):
if root_url is None:
return
if root_url not in self.new_urls and root_url not in self.old_urls:
self.new_urls.add(root_url)
def has_new_url(self):
return len(self.new_urls) != 0
def get_new_url(self):
new_url = self.new_urls.pop()
self.old_urls.add(new_url)
return new_url
def add_new_urls(self, new_urls):
if new_urls is None or len(new_urls) == 0:
return
for url in new_urls:
self.add_new_url(url)
網(wǎng)頁下載器
html_downloader.py文件
import urllib.request
class HtmlDownloader(object):
def download(self, new_url):
if new_url is None:
return None
response = urllib.request.urlopen(new_url)
if response.getcode() != 200:
return None
return response.read()
網(wǎng)頁解析器
html_parse.py文件
import re
import urllib
from urllib import parse
from bs4 import BeautifulSoup
class HtmlParser(object):
def parse(self, new_url, html_cont):
if new_url is None or html_cont is None:
return
soup = BeautifulSoup(html_cont,'html.parser' )
new_urls = self._get_new_urls(new_url,soup)
new_data = self._get_new_data(new_url,soup)
return new_urls,new_data
def _get_new_urls(self, new_url, soup):
new_urls = set()
#獲取要爬取的鏈接
links = soup.find_all('a',href=re.compile(r'/item/\w+'))
for link in links:
new_url1 = link['href']
new_full_url = parse.urljoin(new_url, new_url1)
new_urls.add(new_full_url)
return new_urls
def _get_new_data(self, new_url, soup):
res_data = {}
res_data['url'] = new_url
#<dd class="lemmaWgt-lemmaTitle-title"><h1>Python</h1>
#獲取詞條的標(biāo)題
title_node = soup.find('dd',class_='lemmaWgt-lemmaTitle-title').find('h1')
res_data['title'] = title_node.get_text()
#獲取詞條的內(nèi)容
summary_node = soup.find('div',class_='lemma-summary')
res_data['summary'] = summary_node.get_text()
return res_data
輸出器
html_outputer.py文件
class HtmlOutputer(object):
def __init__(self):
self.datas = []
def collect_data(self, new_data):
if new_data is None:
return
print(new_data['summary'])
self.datas.append(new_data)
#數(shù)據(jù)庫操作函數(shù)
def into_mysql(self):
i = 0
for data in self.datas:
conn = pymysql.Connect(
host='127.0.0.1',
user='你的用戶名',
password='你的密碼',
db='數(shù)據(jù)庫名稱',
port=3306,
charset='utf8mb4'
)
try:
cursor = conn.cursor()
i += 1
sql = 'insert into `urls`(`id`,`urlname`,`urlhref`,`urlcontent`)values(%s,%s,%s,%s)'
#執(zhí)行上面的sql語句 并傳入4個(gè)參數(shù)
#分別是id,title叠纷,url噩凹,content
cursor.execute(sql, (i, data['title'],data['url'],data['summary']))
conn.commit()
finally:
conn.close()
注:關(guān)于編碼問題 因?yàn)樵摼W(wǎng)頁就是采用的utf-8編碼 所以無需調(diào)用encode()方法編碼 直接data['summary']的內(nèi)容就是正常顯示 若將數(shù)據(jù)寫入文件 則需要第二個(gè)參數(shù)傳入encoding='' 指定文件編碼方式 測(cè)試時(shí)盡量不用Windows系統(tǒng)自帶的IE瀏覽器 由于默認(rèn)編碼問題 會(huì)導(dǎo)致顯示亂碼(當(dāng)時(shí)就是被這個(gè)問題困擾) 換用記事本或其它瀏覽器就正常顯示了
最后點(diǎn)擊運(yùn)行
運(yùn)行 爬取網(wǎng)頁正常 然后我們?nèi)タ纯磾?shù)據(jù)庫
數(shù)據(jù)庫也導(dǎo)入成功了 到此 我們的需求就完成了 最后附上github地址