Python爬虫——爬取豆瓣读书信息并存入数据库

这两天爬了豆瓣读书的十万条左右的书目信息,用时将近一天,现在趁着这个空闲把代码总结一下,还是菜鸟,都是用的最简单最笨的方法,还请路过的大神不吝赐教。
第一步,先看一下我们需要的库:

import requests                       #用来请求网页
from bs4 import BeautifulSoup         #解析网页
import time          #设置延时时间,防止爬取过于频繁被封IP号
import re            #正则表达式库
import pymysql       #由于爬取的数据太多,我们要把他存入MySQL数据库中,这个库用于连接数据库
import random        #这个库里用到了产生随机数的randint函数,和上面的time搭配,使爬取间隔时间随机

这个是豆瓣的网址:https://book.douban.com/tag/?view=type&icn=index-sorttags-all
我们要从这里获取所有分类的标签链接,进一步去爬取里面的信息,代码先贴上来:

import requests
from bs4 import BeautifulSoup       #导入库

url="https://book.douban.com/tag/?icn=index-nav"
wb_data=requests.get(url)                #请求网址
soup=BeautifulSoup(wb_data.text,"lxml")  #解析网页信息
tags=soup.select("#content > div > div.article > div > div > table > tbody > tr > td > a")
     #根据CSS路径查找标签信息,CSS路径获取方法,右键-检查-copy selector,tags返回的是一个列表
for tag in tags:    
       tag=tag.get_text()    #将列表中的每一个标签信息提取出来
       helf="https://book.douban.com/tag/"   
          #观察一下豆瓣的网址,基本都是这部分加上标签信息,所以我们要组装网址,用于爬取标签详情页
       url=helf+str(tag)  
       print(url)    #网址组装完毕,输出

以上我们便爬取了所有标签下的网址,我们将这个文件命名为channel,并在channel中创建一个channel字符串,放上我们所有爬取的网址信息,等下爬取详情页的时候直接从这里提取链接就好了,如下:

channel='''   
      https://book.douban.com/tag/小说     
      https://book.douban.com/tag/外国文学    
      https://book.douban.com/tag/文学    
      https://book.douban.com/tag/随笔     
      https://book.douban.com/tag/中国文学    
      https://book.douban.com/tag/经典    
      https://book.douban.com/tag/日本文学    
      https://book.douban.com/tag/散文    
      https://book.douban.com/tag/村上春树    
      https://book.douban.com/tag/诗歌    
      https://book.douban.com/tag/童话    
      https://book.douban.com/tag/杂文    
      https://book.douban.com/tag/王小波    
      https://book.douban.com/tag/儿童文学    
      https://book.douban.com/tag/古典文学    
      https://book.douban.com/tag/张爱玲    
      https://book.douban.com/tag/名著    
      https://book.douban.com/tag/余华    
      https://book.douban.com/tag/当代文学    
      https://book.douban.com/tag/钱钟书    
      https://book.douban.com/tag/鲁迅    
      https://book.douban.com/tag/外国名著    
      https://book.douban.com/tag/诗词    
      https://book.douban.com/tag/茨威格    
      https://book.douban.com/tag/米兰·昆德拉    
      https://book.douban.com/tag/杜拉斯    
      https://book.douban.com/tag/港台    
      https://book.douban.com/tag/漫画    
      https://book.douban.com/tag/绘本    
      https://book.douban.com/tag/推理    
      https://book.douban.com/tag/青春    
      https://book.douban.com/tag/言情    
      https://book.douban.com/tag/科幻    
      https://book.douban.com/tag/东野圭吾    
      https://book.douban.com/tag/悬疑    
      https://book.douban.com/tag/武侠    
      https://book.douban.com/tag/奇幻    
      https://book.douban.com/tag/韩寒    
      https://book.douban.com/tag/日本漫画    
      https://book.douban.com/tag/耽美    
      https://book.douban.com/tag/亦舒    
      https://book.douban.com/tag/三毛    
      https://book.douban.com/tag/安妮宝贝    
      https://book.douban.com/tag/网络小说    
      https://book.douban.com/tag/推理小说    
      https://book.douban.com/tag/郭敬明    
      https://book.douban.com/tag/穿越    
      https://book.douban.com/tag/金庸    
      https://book.douban.com/tag/轻小说    
      https://book.douban.com/tag/阿加莎·克里斯蒂    
      https://book.douban.com/tag/几米    
      https://book.douban.com/tag/魔幻    
      https://book.douban.com/tag/张小娴    
      https://book.douban.com/tag/幾米    
      https://book.douban.com/tag/青春文学    
      https://book.douban.com/tag/科幻小说    
      https://book.douban.com/tag/J.K.罗琳    
      https://book.douban.com/tag/高木直子    
      https://book.douban.com/tag/古龙    
      https://book.douban.com/tag/沧月    
      https://book.douban.com/tag/落落    
      https://book.douban.com/tag/张悦然    
      https://book.douban.com/tag/蔡康永    
      https://book.douban.com/tag/历史    
      https://book.douban.com/tag/心理学    
      https://book.douban.com/tag/哲学    
      https://book.douban.com/tag/传记    
      https://book.douban.com/tag/文化    
      https://book.douban.com/tag/社会学    
      https://book.douban.com/tag/艺术    
      https://book.douban.com/tag/设计    
      https://book.douban.com/tag/政治    
      https://book.douban.com/tag/社会    
      https://book.douban.com/tag/建筑    
      https://book.douban.com/tag/宗教    
      https://book.douban.com/tag/电影    
      https://book.douban.com/tag/数学    
      https://book.douban.com/tag/政治学    
      https://book.douban.com/tag/回忆录    
      https://book.douban.com/tag/思想    
      https://book.douban.com/tag/中国历史    
      https://book.douban.com/tag/国学    
      https://book.douban.com/tag/音乐    
      https://book.douban.com/tag/人文    
      https://book.douban.com/tag/人物传记    
      https://book.douban.com/tag/戏剧          
      https://book.douban.com/tag/生活    
      https://book.douban.com/tag/成长    
      https://book.douban.com/tag/励志    
      https://book.douban.com/tag/心理     
      https://book.douban.com/tag/摄影    
      https://book.douban.com/tag/女性    
      https://book.douban.com/tag/职场    
      https://book.douban.com/tag/美食    
      https://book.douban.com/tag/教育    
      https://book.douban.com/tag/游记    
      https://book.douban.com/tag/灵修    
      https://book.douban.com/tag/健康    
      https://book.douban.com/tag/情感    
      https://book.douban.com/tag/手工    
      https://book.douban.com/tag/养生    
      https://book.douban.com/tag/两性    
      https://book.douban.com/tag/人际关系    
      https://book.douban.com/tag/家居    
      https://book.douban.com/tag/自助游    
      https://book.douban.com/tag/经济学    
      https://book.douban.com/tag/管理    
      https://book.douban.com/tag/经济    
      https://book.douban.com/tag/商业    
      https://book.douban.com/tag/金融    
      https://book.douban.com/tag/投资    
      https://book.douban.com/tag/营销    
      https://book.douban.com/tag/创业    
      https://book.douban.com/tag/理财    
      https://book.douban.com/tag/广告       
      https://book.douban.com/tag/股票    
      https://book.douban.com/tag/企业史    
      https://book.douban.com/tag/策划    
      https://book.douban.com/tag/科普    
      https://book.douban.com/tag/互联网    
      https://book.douban.com/tag/编程    
      https://book.douban.com/tag/科学    
      https://book.douban.com/tag/交互设计    
      https://book.douban.com/tag/用户体验    
      https://book.douban.com/tag/算法    
      https://book.douban.com/tag/web    
      https://book.douban.com/tag/科技    
      https://book.douban.com/tag/UE    
      https://book.douban.com/tag/通信    
      https://book.douban.com/tag/交互         
      https://book.douban.com/tag/UCD    
      https://book.douban.com/tag/神经网络    
      https://book.douban.com/tag/程序              
     '''

现在,我们开始第二个程序。

QQ图片20160915233329.png

标签页下每一个图片的信息基本都是这样的,我们可以直接从这里提取到标题,作者,出版社,出版时间,价格,评价人数,以及评分等信息(有些外国作品还会有译者信息),提取方法与提取标签类似,也是根据CSS路径提取。
我们先用一个网址来实验爬取:

url="https://book.douban.com/tag/科技"
wb_data = requests.get(url)
soup = BeautifulSoup(wb_data.text.encode("utf-8"), "lxml")
tag=url.split("?")[0].split("/")[-1]    #从链接里面提取标签信息,方便存储
detils=soup.select("#subject_list > ul > li > div.info > div.pub")  #抓取作者,出版社信息,稍后我们用spite()函数再将他们分离出来
scors=soup.select("#subject_list > ul > li > div.info > div.star.clearfix > span.rating_nums")   #抓取评分信息
persons=soup.select("#subject_list > ul > li > div.info > div.star.clearfix > span.pl")    #评价人数
titles=soup.select("#subject_list > ul > li > div.info > h2 > a")   #书名
#以上抓取的都是我们需要的html语言标签信息,我们还需要将他们一一分离出来
for detil,scor,person,title in zip(detils,scors,persons,titles): 
                              #用一个zip()函数实现一次遍历
#因为一些标签中有译者信息,一些标签中没有,为避免错误,所以我们要用一个try来把他们分开执行   
      try:       
           author=detil.get_text().split("/",4)[0].split()[0]     #这是含有译者信息的提取办法,根据“/”  把标签分为五部分,然后依次提取出来
           yizhe= detil.get_text().split("/", 4)[1]            
           publish=detil.get_text().split("/", 4)[2]           
           time=detil.get_text().split("/", 4)[3].split()[0].split("-")[0]   #时间我们只提取了出版年份  
           price=ceshi_priceone(detil)        #因为价格的单位不统一,我们用一个函数把他们换算为“元”
           scoe=scor.get_text() if True else ""    #有些书目是没有评分的,为避免错误,我们把没有评分的信息设置为空    
           person=ceshi_person(person)      #有些书目的评价人数显示少于十人,爬取过程中会出现错误,用一个函数来处理
           title=title.get_text().split()[0]   
#当没有译者信息时,会显示IndexError,我们分开处理
      except IndexError:      
            try:               
                 author=detil.get_text().split("/", 3)[0].split()[0]                
                 yizhe=""         #将detil信息划分为4部分提取,译者信息直接设置为空,其他与上面一样      
                 publish=detil.get_text().split("/", 3)[1]                
                 time=detil.get_text().split("/", 3)[2].split()[0].split("-")[0]                
                 price=ceshi_pricetwo(detil)               
                 scoe=scor.get_text() if True else ""                
                 person=ceshi_person(person)                
                 title=title.get_text().split()[0]       
            except (IndexError,TypeError):          
                  continue   
#出现其他错误信息,忽略,继续执行(有些书目信息下会没有出版社或者出版年份,但是数量很少,不影响我们大规模爬取,所以直接忽略)
 except TypeError:      
       continue

#提取评价人数的函数,如果评价人数少于十人,按十人处理
def ceshi_person(person):  
     try:       
          person = int(person.get_text().split()[0][1:len(person.get_text().split()[0]) - 4])   
     except ValueError:       
           person = int(10)   
           return person

#分情况提取价格的函数,用正则表达式找到含有特殊字符的信息,并换算为“元”
def ceshi_priceone(price):   
        price = detil.get_text().split("/", 4)[4].split()    
        if re.match("USD", price[0]):      
                 price = float(price[1]) * 6   
        elif re.match("CNY", price[0]):       
                 price = price[1]  
        elif re.match("\A$", price[0]):       
                 price = float(price[1:len(price)]) * 6   
        else:       
                 price = price[0]    
       return price
def ceshi_pricetwo(price):    
       price = detil.get_text().split("/", 3)[3].split()   
       if re.match("USD", price[0]):       
               price = float(price[1]) * 6   
       elif re.match("CNY", price[0]):       
               price = price[1]   
       elif re.match("\A$", price[0]):        
               price = float(price[1:len(price)]) * 6    
       else:       
               price = price[0]   
       return price

实验成功后,我们就可以爬取数据并导入到数据库中了,以下为全部源码,特殊情况会用注释一一说明。

import requests
from bs4 import BeautifulSoup
import time
import re
import pymysql
from channel import channel   #这是我们第一个程序爬取的链接信息
import random

def ceshi_person(person):  
     try:       
          person = int(person.get_text().split()[0][1:len(person.get_text().split()[0]) - 4])   
     except ValueError:       
           person = int(10)   
     return person

def ceshi_priceone(price):   
        price = detil.get_text().split("/", 4)[4].split()    
        if re.match("USD", price[0]):      
                 price = float(price[1]) * 6   
        elif re.match("CNY", price[0]):       
                 price = price[1]  
        elif re.match("\A$", price[0]):       
                 price = float(price[1:len(price)]) * 6   
        else:       
                 price = price[0]    
        return price

def ceshi_pricetwo(price):    
       price = detil.get_text().split("/", 3)[3].split()   
       if re.match("USD", price[0]):       
               price = float(price[1]) * 6   
       elif re.match("CNY", price[0]):       
               price = price[1]   
       elif re.match("\A$", price[0]):        
               price = float(price[1:len(price)]) * 6    
       else:       
               price = price[0]   
       return price


#这是上面的那个测试函数,我们把它放在主函数中
def mains(url):
      wb_data = requests.get(url)
      soup = BeautifulSoup(wb_data.text.encode("utf-8"), "lxml")
      tag=url.split("?")[0].split("/")[-1]    
      detils=soup.select("#subject_list > ul > li > div.info > div.pub")  
      scors=soup.select("#subject_list > ul > li > div.info > div.star.clearfix > span.rating_nums")   
      persons=soup.select("#subject_list > ul > li > div.info > div.star.clearfix > span.pl")    
      titles=soup.select("#subject_list > ul > li > div.info > h2 > a")   
      for detil,scor,person,title in zip(detils,scors,persons,titles):
            l = []  #建一个列表,用于存放数据
            try:       
                 author=detil.get_text().split("/",4)[0].split()[0] 
                 yizhe= detil.get_text().split("/", 4)[1]            
                 publish=detil.get_text().split("/", 4)[2]           
                 time=detil.get_text().split("/", 4)[3].split()[0].split("-")[0]   
                 price=ceshi_priceone(detil)  
                 scoe=scor.get_text() if True else ""     
                 person=ceshi_person(person)   
                 title=title.get_text().split()[0]   
            except IndexError:      
                  try:               
                       author=detil.get_text().split("/", 3)[0].split()[0]                
                       yizhe=""          
                       publish=detil.get_text().split("/", 3)[1]                
                       time=detil.get_text().split("/", 3)[2].split()[0].split("-")[0]                
                       price=ceshi_pricetwo(detil)               
                       scoe=scor.get_text() if True else ""                
                       person=ceshi_person(person)                
                       title=title.get_text().split()[0]       
                  except (IndexError,TypeError):          
                        continue   

       except TypeError:      
             continue
       l.append([title,scoe,author,price,time,publish,person,yizhe,tag])
                    #将爬取的数据依次填入列表中
 

       sql="INSERT INTO allbooks values(%s,%s,%s,%s,%s,%s,%s,%s,%s)"  #这是一条sql插入语句
       cur.executemany(sql,l)   #执行sql语句,并用executemary()函数批量插入数据库中
       conn.commit()

#主函数到此结束


# 将Python连接到MySQL中的python数据库中
conn = pymysql.connect( user="root",password="123123",database="python",charset='utf8')
cur = conn.cursor()

cur.execute('DROP TABLE IF EXISTS allbooks')   #如果数据库中有allbooks的数据库则删除
sql = """CREATE TABLE allbooks(      
        title CHAR(255) NOT NULL,      
        scor CHAR(255),      
        author CHAR(255),     
        price CHAR(255),     
        time CHAR(255),    
        publish CHAR(255),     
        person CHAR(255),     
        yizhe CHAR(255),     
        tag CHAR(255)       
 )"""
cur.execute(sql)  #执行sql语句,新建一个allbooks的数据库


start = time.clock()   #设置一个时钟,这样我们就能知道我们爬取了多长时间了
for urls in channel.split():    
      urlss=[urls+"?start={}&type=T".format(str(i)) for i in range(0,980,20)]   #从channel中提取url信息,并组装成每一页的链接
      for url in urlss:       
             mains(url)       #执行主函数,开始爬取
             print(url)        #输出要爬取的链接,这样我们就能知道爬到哪了,发生错误也好处理
             time.sleep(int(format(random.randint(0,9))))   #设置一个随机数时间,每爬一个网页可以随机的停一段时间,防止IP被封
end = time.clock()
print('Time Usage:', end - start)    #爬取结束,输出爬取时间
count = cur.execute('select * from allbooks')
print('has %s record' % count)       #输出爬取的总数目条数

# 释放数据连接
if cur:   
     cur.close()
if conn:   
     conn.close()

这样,一个程序就算完成了,豆瓣的书目信息就一条条地写进了我们的数据库中,当然,在爬取的过程中,也遇到了很多问题,比如标题返回的信息拆分后中会有空格,写入数据库中会出现错误,所以只截取了标题的第一部分,因而导致数据库中的一些书名不完整,过往的大神如果有什么办法,还请指教一二。
等待爬取的过程是漫长而又欣喜的,看着电脑上一条条信息被刷出来,成就感就不知不觉涌上心头;然而如果你吃饭时它在爬,你上厕所时它在爬,你都已经爬了个山回来了它还在爬时,便会有点崩溃了,担心电脑随时都会坏掉(还是穷学生换不起啊啊啊啊~)
所以,还是要好好学学设置断点,多线程,以及正则,路漫漫其修远兮,吾将上下而求索共勉

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容