python爬虫中的mongo实践

目标

  1. 获取全本小说网的小说封面
  2. 保存封面图片到mongo数据库中
  3. 记录封面图片对应的小说信息

分析

  1. 本次使用requests作为http请求工具
  2. 获取小说封面的方式采用爬虫分类型、分页爬去小说封面地址
  3. 向图片的原地址发送http的get请求,获取response的content就是图片的二进制数据了
  4. 本次存储图片的方式并采用系统自带的文件系统,而是使用mongodb的GridFS
  5. 将步骤3中的content数据put到gridfs中获取文件id
  6. 从步骤2中获取小说的名称等信息,与步骤5中的id做映射,保存到novel集合集中
    注:步骤6在是可以将小说的其他信息一同保存至gridfs的files集合中的,使用方法会在代码中进行注释

示例

import requests
from bs4 import BeautifulSoup
import pymongo
import gridfs
import time

# 获取mongoClient对象
client = pymongo.MongoClient("localhost", 27017)
# 获取使用的database对象
db = client.test
# 获取图片存储集合
fs = gridfs.GridFS(db, "images")


def save_pic_to_disk():
    """
    将数据库中文件转存到本地文件系统
    :return: 无
    """
    fss = fs.find()
    for fl in fss:
        print(fl.md5)
        tp_file = open('d:/img/' + fl.md5 + '.jpg', "wb")
        tp_file.write(fl.read())
        tp_file.close()


def mongodb_delete(title, author):
    """
    根据小说标题和作者删除其小说封面信息
    例如:mongodb_delete('桃花扇','孔尚任')
    :param title 小说标题
    :param author 小说作者
    """
    record = db.novel.find_one({"title": title, "author": author})
    print(record)
    _id = record.get("_id")
    _img = record.get("imag")
    db.novel.remove({"_id": _id})
    fs.delete(_img)


def iterator(url):
    """
    遍历指定地址下的小说条目
    获取小说封面、标题和作者信息
    然后保存至数据库
    最后获取递归到下一页进行遍历
    :param url: 小说列表页面地址
    :return: 无返回
    """
    print(url)

    # 获取页面html,并使用beautifulsoup进行解析
    rs = requests.get(url).content.decode("gbk")
    bs_obj = BeautifulSoup(rs, "html.parser")
    content = bs_obj.find("div", {"id": "content"})

    # 获取小说列表,并遍历小说数据
    novels = bs_obj.findAll("div", {"class": "Sum Search_line"})
    for novel in novels:
        # 获取小说的名称、索引地址、作者
        name = novel.find("h2").find("a").get_text()
        index = novel.find("h2").find("a").get("href")
        author = novel.find("em").find("a").get_text()

        # 获取小说封面,并使用gridfs保存至mongo
        img = novel.find("img")
        rs = requests.get(img.get("src"))

        # 这种方式是将小说的题目等信息与封面图片保存在一起
        # fs.put(rs.content,title=name, author=author, url=index)

        # 这种方式进行保存图片文件,然后记录文件编号,比较像关系数据库的使用方式
        _id = fs.put(rs.content)
        db.novel.save(dict(title=name, author=author, url=index, imag=_id, time=time.time()))

    # 获取下一页链接,如果存在下一页就进行递归遍历
    next_page = content.find("div", {"id": "pagelink"}).find("a", {"class": "next"})
    if next_page:
        iterator(next_page.get("href"))


# 遍历全本小说网的小说信息
# 从小说站点的导航上可以看出,该站点小说分为11个类型,而且类型编号从1开始递增
for i in range(1, 12):
    iterator('http://www.wanbenxiaoshuo.net/sort/' + str(i) + '_1.html')

# 关闭资源
client.close()

总结

  • pymongo的简单使用

在上述代码中使用pymongo作为python操作mongodb的工具,除了完成目标要求,还额外书写了两个方法用于体验pymongo的使用。总结一下pymongo的简单使用方法:
1. 获取Client对象

client = pymongo.MongoClient("localhost", 27017)
  1. 使用client获取database对象
db = client.test
  1. 如果需要可以使用database对象获取GridFS
fs = gridfs.GridFS(db, "images")
  1. 使用database对象存储document,python中可以直接存储字典数据
db.novel.save(dict(title=name, author=author, url=index, imag=_id, time=time.time()))
db.novel.remove({"_id": _id})
novels = bs_obj.findAll("div", {"class": "Sum Search_line"})
  1. 可以使用GridFS对文件进行存储、删除等操作
fs.put(rs.content,title=name, author=author, url=index)
fs.delete(_img)
fss = fs.find()
  1. 遍历查询结果,直接使用 for-in即可
for fl in fss:
    print(fl.md5)
  1. 使用完毕后需要关闭资源
client.close()
  • request处理中文乱码问题:

request中貌似并没有直接处理字符集的工具,所以只能自己对相应体中的content进行编码判断,然后再decode。

rs = requests.get(url).content.decode("gbk")

到目前为止,我还没有发现比较有效的字符集判断方法,以前看过chardet,但是我认为那种判断方式效率过于底下,所以我还是使用的人工观测,然后直接指定字符集。

你可能感兴趣的:(爬虫,Python,MongoDB)