不用scrapy框架爬取豆瓣所有图书信息

一、spider爬虫

爬虫网络爬虫(又被称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取服务器中数据的程序或者脚本。

爬虫的策略一般都遵循广度优先原则,一层一层数据的进行爬取,一般的网站深度不会太深,除非是重要的机密的那些网站。

二、基于python实现豆瓣爬取

如果能弄懂自己搭建的爬虫类,对于学习scrapy框架乃至自己搭建爬虫框架会有很大的帮助,毕竟再大的框架也离不开这些基本的原理,请先运行代码,对照注释和代码讲解进行学习。

A、可以直接运行的代码,爬取豆瓣,得到成就感之后我们回头看代码。

由于讲解原理会令人产生厌恶,所以先贴上代码让各位直接运行出结果,看到结果的成就感再回头学代码效率会高很多。
代码如下,运行即可爬取豆瓣网,并将爬取到的数据已.csv的保存

import ssl
import bs4
import re
import requests
import csv
import codecs
import time
from urllib import request, error

context = ssl._create_unverified_context()

class DouBanSpider:
    def __init__(self):
        #定义请求头  模拟浏览器访问豆瓣服务器
        self.userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"
        self.headers = {"User-Agent": self.userAgent}
        
    # 拿到豆瓣图书的分类标签
    def getBookCategroies(self):
        try:
            #需要爬去的网站的url,这个网址是豆瓣的网址;
            url = "https://book.douban.com/tag/?view=type&icn=index-sorttags-all"
            #调用urlopen方法去访问豆瓣url,这时我们的脚本会模拟浏览器发送一个请求
            response = request.urlopen(url, context=context)
            #在豆瓣服务器接收到请求之后,会给我们一个response
            content = response.read().decode("utf-8")
            return content
        except error.HTTPError as identifier:
            print("errorCode: " + identifier.code + "errrorReason: " + identifier.reason)
            return None

    # 找到每个标签的内容
    def getCategroiesContent(self):
        content = self.getBookCategroies()
        if not content:
            print("页面抓取失败...")
            return None
        #用bs4对返回的json文件进行解析
        soup = bs4.BeautifulSoup(content, "lxml")
        #用正则将所有的标签内容匹配出来
        categroyMatch = re.compile(r"^/tag/*")
        categroies = []
        for categroy in soup.find_all("a", {"href": categroyMatch}):
            if categroy:
                categroies.append(categroy.string)
        return categroies

    # 拿到每个标签的链接
    def getCategroyLink(self):
        categroies = self.getCategroiesContent()
        categroyLinks = []
        for item in categroies:
            link = "https://book.douban.com/tag/" + str(item)
            categroyLinks.append(link)
        return categroyLinks
	#进入标签对应的书籍列表,爬去书籍信息
    def getBookInfo(self, categroyLinks):
        #打开,csv文档,将爬去的数据存进去
        self.setCsvTitle()
        categroies = categroyLinks
        try:
        	#遍历每一个标签对应的url,请求每一个标签页,并接收服务器的response
            for link in categroies:
                print("正在爬取:" + link)
                bookList = []
                response = requests.get(link)
                soup = bs4.BeautifulSoup(response.text, 'lxml')
                bookCategroy = soup.h1.string
                #解析接受到的json数据,将我们要爬取的数据,使用正则依次匹配需要爬取的内容
                for book in soup.find_all("li", {"class": "subject-item"}):
                    bookSoup = bs4.BeautifulSoup(str(book), "lxml")
                    #bs4标签属性得到  每一本书名
                    bookTitle = bookSoup.h2.a["title"]
                    #正则匹配  作者出版社信息
                    bookAuthor = bookSoup.find("div", {"class": "pub"})
                    #正则匹配  评价数量
                    bookComment = bookSoup.find("span", {"class": "pl"})
                    #bs4解析得到   书本的内容简介
                    bookContent = bookSoup.li.p
                    # print(bookContent)
                    #如果这些值非空,则将爬取到的信息保存
                    if bookTitle and bookAuthor and bookComment and bookContent:
                        bookList.append([bookTitle.strip(),bookCategroy.strip() , bookAuthor.string.strip(),
                                         bookComment.string.strip(), bookContent.string.strip()])
                #将爬取的数据保存至csv内
                self.saveBookInfo(bookList)
                time.sleep(3)

            print("爬取结束....")

        except error.HTTPError as identifier:
            print("errorCode: " + identifier.code + "errrorReason: " + identifier.reason)
            return None

    def setCsvTitle(self):
        csvFile = codecs.open("data/data.csv", 'a', 'utf_8_sig')
        try:
            writer = csv.writer(csvFile)
            writer.writerow(['title', 'tag', 'info', 'comments', 'content'])
        finally:
            csvFile.close()

    def saveBookInfo(self, bookList):
        bookList = bookList
        csvFile = codecs.open("data/data.csv", 'a', 'utf_8_sig')
        try:
            writer = csv.writer(csvFile)
            for book in bookList:
                writer.writerow(book)
        finally:
            csvFile.close()

    def start(self):
        categroyLink = self.getCategroyLink()
        self.getBookInfo(categroyLink)


douBanSpider = DouBanSpider()
douBanSpider.start()

运行结果之后得到了data文件夹下的.csv文件,可得到爬取的13w条记录:
不用scrapy框架爬取豆瓣所有图书信息_第1张图片
不用scrapy框架爬取豆瓣所有图书信息_第2张图片

B、 分析代码

程序核心为定义的Doubanspider类,下面分析一波doubanSpider(可以对照代码的注释进行理解)
(1)初始化
定义了请求头,模拟请求头访问豆瓣服务器,否被会被forbidden 。
在浏览器向任意服务器发一个请求,按F12->Network,选中一个请求,查看,在request headers可以看到对应值,可自行更改请求头后运行程序
不用scrapy框架爬取豆瓣所有图书信息_第3张图片
(2)拿到下图中图书的分类标签
打开豆瓣url,按F12,我们看Elements,我们可以做找到显示的图书分类标签对应的div模块,如下图
不用scrapy框架爬取豆瓣所有图书信息_第4张图片
(仔细看上图,右边div的name属性,就是书籍的分类标签,所以我们在解析json文件的时候,只需要应用正则将这些标签值匹配出来,我们就可以拿到所有的标签的值了)
运行spider时,我们request模块会先向服务器发送一个请求,告诉服务器我们要访问他了,这是服务器会返回我们response,在我们拿到了服务器的response之后,其实我们是拿到的json数据,而数据的内容便是这个页面显示的html5 代码,我们的标签值就藏在html5代码中的div模块之中,好了我们现在已经拿到了分类标签。
(3)找到每个标签的内容
我们观察html5代码(如下图),在文学的一类中,对应的‘小说’、‘外国文学’、‘文学等等’这些标签均以 {小说} 这样类似的格式出现,所以我们只需要用正则将这部分内容匹配出来之后,就能拿到标签里面的具体内容了。
不用scrapy框架爬取豆瓣所有图书信息_第5张图片
(3)拿到每个标签对应的url
因为我们现在只是拿到了标签的值,而书籍的详细列表藏在标签的超链接url里,所以我们要爬取数据就要进入到对应的url当中。
我们点开‘小说’、‘外国文学’。。。观察url的规律:
可以找到规律 url=‘’https://book.douban.com/tag/‘’+标签值
不用scrapy框架爬取豆瓣所有图书信息_第6张图片
(4)爬取每个标签下的图书信息
进入文学->外国文学标签页,通过请求这些页面,接受到服务器的json数据,通过bs4解析html5代码,再用正则依次匹配出我们的书籍的信息:
看下图 右侧console栏:

不用scrapy框架爬取豆瓣所有图书信息_第7张图片
(5)文件保存、爬虫运行方法就不做解释了。

至此我们就可以运行自己的爬虫了。

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