本文主要介绍使用Python爬虫爬取Python百度词条的信息 主要参考慕课网的《开发简单爬虫》以及一些数据库操作
开发工具
---工欲善其事 必先利其器
首先 这里开发工具用的Python3.6+Pycharm+MySQL5.7+SQLyog
前面2个的安装直接网上搜下教程一大堆 而且免去了配置环境变量的操作,MySQL数据库(安装教程也一大堆)现在最新版是5.7 它的安装与之前的有点不同
注意到没 安装时多了一个必须选项 安装InnoDB时设置password 然后再填入即可 其它步骤和一般软件没什么区别
然后去搜索引擎下载SQLyog工具(用Pycharm自带的dataBase应该也可以 有兴趣的小伙伴可以去试试 ) 连接数据库
点击连接 出错的可以看看 进入控制面板→管理工具→服务→看MySQL service是否打开 连接好后创建数据库baikeurl 然后建url表
爬虫的架构及具体流程
1.传入目标url后调用URL管理器
2.URL管理器对URL进行具体的判断与检索后传入网页下载器
3.网页下载器工作后将网页传入网页解析器
4.将解析后的内容(url,title,content等)传入输出器
5.最后输出器进行数据操作(写入文件 导入数据库等)
整个过程采用了严格的面向对象思想 每一过程具体的函数都封装在相应文件中
实例分析
要爬取的链接:http://baike.baidu.com/item/Python
通过浏览器的开发者工具分析可知 百度百科的词条
链接:/item/……的形式
标题: <dd class="lemmaWgt-lemmaTitle-title"><h1>……</h1> 内容:<div class="lemma-summary">……</div>
废话不多说 直接上代码 关键地方带注释 一个包括5个文件
爬虫调度端(主页)
spider.py文件
import html_downloader
import html_outputer
import html_parser
import url_manager
#爬虫主函数
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()
#抓取过程函数
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)
网页下载器
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()
网页解析器
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>
#获取词条的标题
title_node = soup.find('dd',class_='lemmaWgt-lemmaTitle-title').find('h1')
res_data['title'] = title_node.get_text()
#获取词条的内容
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)
#数据库操作函数
def into_mysql(self):
i = 0
for data in self.datas:
conn = pymysql.Connect(
host='127.0.0.1',
user='你的用户名',
password='你的密码',
db='数据库名称',
port=3306,
charset='utf8mb4'
)
try:
cursor = conn.cursor()
i += 1
sql = 'insert into `urls`(`id`,`urlname`,`urlhref`,`urlcontent`)values(%s,%s,%s,%s)'
#执行上面的sql语句 并传入4个参数
#分别是id,title,url,content
cursor.execute(sql, (i, data['title'],data['url'],data['summary']))
conn.commit()
finally:
conn.close()
注:关于编码问题 因为该网页就是采用的utf-8编码 所以无需调用encode()方法编码 直接data['summary']的内容就是正常显示 若将数据写入文件 则需要第二个参数传入encoding='' 指定文件编码方式 测试时尽量不用Windows系统自带的IE浏览器 由于默认编码问题 会导致显示乱码(当时就是被这个问题困扰) 换用记事本或其它浏览器就正常显示了
最后点击运行
运行 爬取网页正常 然后我们去看看数据库
数据库也导入成功了 到此 我们的需求就完成了 最后附上github地址