python爬取小说基本信息_python实战项目:爬取某小说网

项目文档:

项目简介:

爬取某小说网首页中的全部小说,并储存到数据库中

项目版本 :python2.7.12

项目源码:

源码已上传 github: 源码github

项目总览:

1. 爬取小说首页中全部小说url

2. 爬取小说详情内容,章节url

3. 爬取章节信息

项目流程:

1. 爬取首页中的所有小说url

1. 获得首页html

2. 解析html

1) 获得小说url

3. 储存到数据库

1) 储存小说url

2. 爬取小说详情内容,章节url

1. 获得小说详情html

2. 解析html

1) 获得小说详情信息

2) 获得小说章节url

3. 储存到数据库

1) 储存小说详情信息

2) 储存章节url

3. 爬取章节信息

1. 获得章节html

2. 解析html

1) 获得章节信息

3. 储存到数据库

1) 储存章节信息

由上面流程可看出每个流程均可抽象为三个层次

1. 获得html

2. 解析html

3. 存储信息到数据库

因此可以抽象出三个功能:下载功能,解析功能,存储功能

项目中异常的处理:

项目中主要是 url的下载,解析中可能会出现一些异常,我们定义 出现此类异常则跑出ValueError异常,并跳过当前url,进行下一个url的爬取,避免程序的崩溃

项目结构:

46d1b1cd127b

image.png

ESBook 项目根目录

bin 保存二进制可执行文件

books 项目目录 存放py文件

data 存放下载的小说封面

docs 存储项目文档 使用sphinx生成的项目文档

tests 测试目录

README 项目说明

requirements.txt 项目依赖第三方包

setup.py python 安装脚本

46d1b1cd127b

image.png

Books目录结构

Callblack 业务逻辑,网页的解析处理(这个就是抽象出来的解析功能)

Logs 项目日志

Util 通用性工具

Bookconfig.py 项目配置文件

link_crawler.py 链接爬取模块

main.py 启动入口模块

46d1b1cd127b

image.png

uitl目录结构:

bookDB 数据库相关操作(抽象出来的存储功能)

Downloaders 下载功能的简单封装(抽象出来的下载功能)

Logger 日志功能

Logging.conf 日志配置文件

mongoQueue 基于mongoDB的url队列

Multiprocessloghandler 支持多进程的TimedRotatingFileHandler

Tools 工具模块

下面看一下项目配置文件Bookconfig.py

将项目配置统一到一个配置文件中,方便后续的更改

#coding=utf-8

"""

项目配置模块

数据库配置

mongodb数据库连接的创建

urls_table 集合的创建以及索引 book_url 的创建

urls_table 小说url表单,储存爬取的小说url

cha_urls_table 集合的创建以及索引 chapter_url的创建

cha_urls_table 章节url表单,储存爬取的小说章节url

books_table 集合的创建以及索引 book_id 的创建

books_table 小说表单,储存爬取的小说详情内容

chapters_table 集合的创建以及联合索引 book_id -- chapter_id 的创建

chapters_table 章节表单,储存爬取的小说章节内容

日志配置

consloe_logger 输出日志到控制台 info级别

error_logger 输出日志到日志文件 和 控制台 error级别

url状态 :数据库集合中url的状态

OUTSTANAING = 0 未处理

PROCESSING = 1 待处理

COMPLETE = 2 已处理

ERROR = 3 产生异常的url

"""

import pymongo

from books.util.logger import MyLogger

OUTSTANAING = 0 # 未处理

PROCESSING = 1 # 待处理

COMPLETE = 2 # 已处理

ERROR = 3 # 产生异常的url

#数据库连接创建

client = pymongo.MongoClient('localhost',27017)

book_db = client['book']

# 小说url表单,储存爬取的小说url

BOOK_URLS_TABLE = book_db['urls_table']

BOOK_URLS_FIELD = 'book_url'

BOOK_URLS_TABLE.create_index([(BOOK_URLS_FIELD,pymongo.DESCENDING)],unique=True)

# 章节url表单,储存爬取的小说章节url

CHA_URLS_TABLE = book_db['cha_urls_table']

CHA_URLS_FIELD = 'chapter_url'

CHA_URLS_TABLE.create_index([(CHA_URLS_FIELD,pymongo.DESCENDING)],unique=True)

# 小说表单,储存爬取的小说详情内容

BOOKS_TABLE = book_db['books_table']

BOOKS_FIELD = 'book_id'

BOOKS_TABLE.create_index([(BOOKS_FIELD,pymongo.DESCENDING)],unique=True)

# 章节表单,储存爬取的小说章节信息

# 小说id,章节id 联合索引

CHAPTERS_TABLE = book_db['chapters_table']

CHAPTERS_FIELD = 'chapter_id'

# 复合唯一索引,由book_id -- chapter_id 确认一条记录的唯一性

CHAPTERS_TABLE.create_index([(BOOKS_FIELD, pymongo.DESCENDING), (CHAPTERS_FIELD, pymongo.DESCENDING)], unique=True)

# 日志

# consloe_logger 输出日志到控制台 info级别

# error_logger 输出日志到日志文件 和 控制台 error级别

CONSOLE_LOGGER = MyLogger.getLogger('consolelogger')

ERROR_LOGGER = MyLogger.getLogger('errorlogger')

我们在看一下 link_crawler.py 模块

link_crawler.py 模块是项目的主体模块。

link_crawler.py 模块主要分三部分

1. 小说首页的爬取

2. 小说详情页的爬取

3. 小说章节页的爬取

小说首页的爬取

scrape_callblack即为解析小说首页的具体实现

def book_crawler(seen_url,delay=5,num_retries=3,encoding='utf-8',headers=None,scrape_callblack=None,cache=None):

"""小说首页爬取,获得首页中所有小说url,并存储到urls队列中

:param seen_url 小说主页url

:param delay 请求间隔时间

:param num_retries 下载错误时重试次数

:param encoding 网页编码

:param headers HTTP请求头信息

:param scrape_callblack 回调函数,用于处理具体业务逻辑

:param cache 数据缓存

:raise ValueError url解析失败则抛出

"""

# 待爬取URL

crawl_queue = seen_url if isinstance(seen_url,list) else [seen_url]

# urls队列,存储小说url

book_queue = MongoQueue(book_config.BOOK_URLS_TABLE,book_config.BOOK_URLS_FIELD)

# 下载功能

D = Downloader(delay=delay,num_retries=num_retries,headers=headers,encoding=encoding,cache=cache)

while crawl_queue:

try:

url = crawl_queue.pop()

try:

html = D(url)

# 解析功能--解析小说首页,返回首页中的所有小说urls

if scrape_callblack:

links = scrape_callblack(url,html)

# 将小说url添加到urls队列中

if links:

[book_queue.push(link) for link in links]

else:

#print '请添加回调处理函数'

break

except ValueError as e:

error_info = u'出现错误跳过当前url 信息为:%s %s ' % (e.message, url)

conlose_logger.error(error_info)

except KeyError as e:

conlose_logger.info(u'小说主页爬取已完成 ')

break

小说详情页的爬取

其中scrape_callblack为 解析小说详情页的具体实现,

小说urls则直接从小说urls队列中获取。

def book_detail_crwler(delay=5,num_retries=3,encoding='utf-8',headers=None,scrape_callblack=None,cache=None):

"""小说详情页爬取,将小说详情储存到数据库中,并将爬取到的章节url存储到urls队列中

:param delay 请求间隔时间

:param num_retries 下载错误时重试次数

:param encoding 网页编码

:param headers HTTP请求头信息

:param scrape_callblack 回调函数,用于处理具体业务逻辑

:param cache 数据缓存

:raise ValueError 详情页解析失败则抛出

"""

#小说url队列,获得小说url

book_queue = MongoQueue(book_config.BOOK_URLS_TABLE,book_config.BOOK_URLS_FIELD)

#章节url队列,储存爬取的章节url

chap_queue = MongoQueue(book_config.CHA_URLS_TABLE,book_config.CHA_URLS_FIELD)

D = Downloader(delay=delay, num_retries=num_retries, headers=headers, encoding=encoding, cache=cache)

while True:

try:

url = book_queue.pop()

try:

html = D(url)

# 解析功能--解析小说详情页并将小说详情储存到数据库中,返回其中的所有小说章节urls

if scrape_callblack:

chap_links = scrape_callblack(url,html)

# 将章节url添加到urls队列中

[chap_queue.push(link) for link in chap_links]

else:

#print '请添加回调处理函数'

break

except ValueError as e:

# 设置当前url状态为 ERROR

book_queue.set_error(url)

error_info = u'出现错误跳过当前url %s 信息为:%s ' % (url,e.message)

error_logger.error(error_info)

except KeyError as e:

#print '处理完成',e

conlose_logger.info(u'小说链接爬取已完成 ')

break

else:

#正常处理完成,设置url状态为 已处理

book_queue.complete(url)

小说章节页的爬取

scrape_callblack为解析章节页面的具体实现

def chpater_crwler(delay=5, num_retries=3, encoding='utf-8', headers=None, scrape_callblack=None, cache=None):

"""章节信息爬取,并储存到数据库

:param delay 请求间隔时间

:param num_retries 下载错误时重试次数

:param encoding 网页编码

:param headers HTTP请求头信息

:param scrape_callblack 回调函数,用于处理具体业务逻辑

:param cache 数据缓存

:raise ValueError 章节页解析失败则抛出

"""

# 章节urls队列

chap_queue = MongoQueue(book_config.CHA_URLS_TABLE, book_config.CHA_URLS_FIELD)

D = Downloader(delay=delay, num_retries=num_retries, headers=headers, encoding=encoding, cache=cache)

while True:

try:

url = chap_queue.pop()

try:

html = D(url)

# 解析功能--解析小说章节页,获得章节内容,并储存到数据库中

if scrape_callblack:

scrape_callblack(url,html)

else:

#print '请添加回调函数'

break

except ValueError as e:

# 设置当前url状态为 ERROR

chap_queue.set_error(url)

error_info = u'出现错误跳过当前url %s 信息为:%s ' % (url,e.message)

error_logger.error(error_info)

except KeyError as e:

conlose_logger.info(u'小说链接爬取已完成 ')

break

else:

# 正常处理完成,设置url状态为 已处理

chap_queue.complete(url)

main.py 模块为 程序入口,也是link_crawler.py的多进程版

book_detail_crawler()与chpater_crwler()是对小说详情页爬取与章节页爬取功能的包装,方便使用多进程时候的调用。

  replace_img()

用来替换不正常的封面图片为默认封面图片

def book_detail_crawler():

"""小说详情页爬取"""

link_crawler.book_detail_crwler(headers={}, scrape_callblack=BookDetailCallblack())

def chpater_crwler():

"""章节页爬取"""

link_crawler.chpater_crwler(headers={}, scrape_callblack=ChapterSpiderCallblack())

def process_crawler(func):

"""启动进程"""

pool = multiprocessing.Pool(processes=8)

for i in range(8):

pool.apply_async(func)

pool.close()

pool.join()

def start():

"""启动爬虫"""

#爬取小说url

book_config.CONSOLE_LOGGER.info(u'开始 -- 爬取主页小说')

url = 'http://www.biquge.com/'

link_crawler.book_crawler(url,headers={},scrape_callblack=BookSpiderCallblack())

time.sleep(10)

#小说详情爬取

book_crawler = link_crawler.book_crawler

book_config.CONSOLE_LOGGER.info(u'开始 -- 小说详情爬取')

process_crawler(book_detail_crawler)

#替换不正常图片为默认封面图片

replace_img()

time.sleep(10)

#章节信息爬取

book_config.CONSOLE_LOGGER.info(u'开始 -- 章节详情爬取')

process_crawler(chpater_crwler)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值