1. # -*- coding = ut-8 -*-
    2. # @Time : 2021/3/25 14:48
    3. # @Author : PHC
    4. # @File spider.py
    5. # @Software : PyCharm
    6. from bs4 import BeautifulSoup #网页解析,获取数据
    7. import re #正则表达式,进行文字匹配
    8. import urllib.request,urllib.error #制定URL,获取网页数据
    9. import xlwt #进行EXCEL操作
    10. import sqlite3 #进行SQLite数据库操作
    11. def main():
    12. baseurl="https://movie.douban.com/top250?start=0"
    13. # 1、爬取网页
    14. datalist=getData(baseurl)
    15. # savepath="豆瓣电影Top250.xls" #保存到Excel中的路径
    16. #保存到数据库中。
    17. dbpath="movie.db"
    18. # 3、保存数据
    19. #------------- 同行缩进--------------------- 同行缩进--------------------------
    20. # saveData(datalist,savepath)
    21. saveDataDB(datalist,dbpath)
    22. #askURL("https://movie.douban.com/top250?start=0") #测试能否访问页面。
    23. #影片详情定制的规则 ----------------------------------------------------------------
    24. findLink=re.compile(r'<a href="(.*?)">') #compile() 创建正则表达式对象,表示规则(字符串得模式)
    25. # (.*?) 其中各符号分别为 ()表示一个组,(即一个整体) . 表示一个字符 * 表示零个或多个 ?表示0次或一次
    26. #影片图片的链接规则
    27. findImgSrc=re.compile(r'<img.*src="(.*?)"',re.S) # re.S让换行符包含在字符中 否则不包含换行符
    28. #影片的片名
    29. findTitle=re.compile(r'<span class="title">(.*)</span>')
    30. #影片的评分
    31. findRating=re.compile(r'<span class="rating_num" property="v:average">(.*)</span>')
    32. #找到评价人数
    33. findJudge=re.compile(r'<span>(\d*)人评价</span>')
    34. #找到概况
    35. findInq=re.compile(r'<span class="inq">(.*?)</span>')
    36. #找到影片相关内容(导演、主演、年份、地区、类别等)
    37. # findBd=re.compile(r'<p class="">(.*)</p>',re.S)
    38. findBd=re.compile(r'<p class="">(.*?)</p>',re.S)
    39. #获取数据,爬取网页 // 获取爬取的网页的数据
    40. def getData(baseurl):
    41. datalist=[]
    42. for i in range(0,10): # 调用获取页面信息的函数·10次
    43. url=baseurl+str(i*25)
    44. html= askURL(url) # 保存获取到的网页源码 执行一次,拿到一页
    45. print("html的类型是",type(html))
    46. # 2、逐一解析数据
    47. soup=BeautifulSoup(html,"html.parser")
    48. for item in soup.find_all('div',class_="item"): # 查找符合要求的字符串,形成列表
    49. # class_ 表示class的属性值是item ---- class 需要加一个下划线,
    50. # print(item) # 测试:查看电影item的全部信息
    51. data= [] # 保存一部电影的所有信息
    52. print(type(item))
    53. item=str(item) # 转型,将item转成字符串
    54. # print(item)
    55. # break
    56. #
    57. # 爬取影片详情的链接 findLink 表示正则表达式的规则,item表示要筛选的字符串
    58. link=re.findall(findLink,item)[0] # [0] 表示找到的所有findLink 中的第一个。re库用来通过正则表达式查找指定的字符串
    59. data.append(link) # 添加链接
    60. # print(link)
    61. # 爬取图片
    62. imgSrc = re.findall(findImgSrc, item)[0]
    63. # print(imgSrc)
    64. data.append(imgSrc) #添加图片
    65. titles=re.findall(findTitle,item) # 片名可能只有一个中文名,也可能有多个名称
    66. if(len(titles)==2):
    67. ctitle=titles[0] #添加中文名
    68. data.append(ctitle)
    69. otitle=titles[1].replace("/","") #去掉无关的 / 符号
    70. data.append(otitle) #添加外国名
    71. else:
    72. data.append(titles[0])
    73. data.append(' ') #外国名留空
    74. rating=re.findall(findRating,item)[0]
    75. data.append(rating) #添加评分
    76. judgeNum=re.findall(findJudge,item)[0]
    77. data.append(judgeNum) #提交评价人数
    78. inq=re.findall(findInq,item)
    79. if len(inq)!=0 :
    80. inq=inq[0].replace("。","") #去掉句号
    81. data.append(inq) #添加概述 (可能有的没有概述)
    82. else:
    83. data.append(" ") #留空
    84. bd=re.findall(findBd,item)[0]
    85. bd=re.sub('<br(\s+)?/>(\s+)?'," ",bd) #去掉<br/>
    86. bd=re.sub('/'," ",bd) #把 / 替换成 " " 空格
    87. data.append(bd.strip()) #去掉前后空格
    88. datalist.append(data) #把处理好的一部电影信息放入datalist
    89. print(datalist)
    90. return datalist
    91. #得到 指定一个URL的网页内容
    92. def askURL(ur):
    93. head={ #模拟浏览器头部信息,向豆瓣服务器发送消息
    94. "User-Agent":"Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 89.0 .4389.90 Safari / 537.36 Edg/ 89.0.774.57"
    95. }
    96. # 用户代理,表示告诉豆瓣服务器我们是什么类型的机器,浏览器(本质上是告诉浏览器,我们可以接收什么水平的文件内容)
    97. request=urllib.request.Request(ur,headers=head) #发送请求
    98. html=""
    99. try:
    100. response=urllib.request.urlopen(request) #获取响应
    101. html=response.read().decode("utf-8") #获取网页内容
    102. # print(html)
    103. except urllib.error.URLError as e: #访问浏览器异常
    104. if hasattr(e,"code"): # 获取错误代码
    105. print(e.code)
    106. if hasattr(e,"reason"): # 获取错误信息
    107. print(e.reason)
    108. return html
    109. # 3、保存数据
    110. def saveData(datalist,savepath):
    111. print("save.....")
    112. book=xlwt.Workbook(encoding="utf-8",style_compression=0) #创建workbook对象
    113. sheet=book.add_sheet("豆瓣电影Top250",cell_overwrite_ok=True) #创建工作表 cell_overwrite_ok=True 单元是否可以覆盖。覆盖以前的内容
    114. col=("电影详情链接","图片链接","影片中文名","影片外国名","评分","评价人数","概况","相关信息")
    115. for i in range(0,8):
    116. sheet.write(0,i,col[i]) #列名
    117. for i in range(0,250):
    118. print("第%d条"%(i+1)) # i+1 表示从第一行从 1 开始
    119. data=datalist[i]
    120. for j in range(0,8):
    121. sheet.write(i+1,j,data[j]) #数据
    122. book.save(savepath) #保存
    123. #保存数据到数据库 (保存之前,先创建数据库)
    124. def saveDataDB(datalist,dbpath): #需要保存的数据 和需要的数据库
    125. init_db(dbpath) #只用运行一遍
    126. conn=sqlite3.connect(dbpath)
    127. cur=conn.cursor()
    128. for data in datalist:
    129. for index in range(len(data)):
    130. if index ==4 or index ==5:
    131. continue
    132. #写入数据库中的字符串必须是字符串类型,即加上双引号。
    133. data[index]='"'+data[index]+'"' #没拼好一行数据,执行一次sql语句。
    134. sql='''
    135. insert into movie250
    136. (info_link,pic_link,cname,ename,score,rated,instroduction,info)
    137. values(%s)'''%",".join(data)
    138. #表示data中的数据用,(逗号相连)
    139. print(sql)
    140. cur.execute(sql)
    141. conn.commit()
    142. cur.close()
    143. conn.close()
    144. # cur.execute(sql)
    145. # print("存到数据库中的步骤")
    146. #存数据得有一个数据库,需要创建数据库
    147. def init_db(dbpath): #创建数据库
    148. sql='''
    149. create table movie250(
    150. id integer primary key autoincrement,
    151. info_link text,
    152. pic_link text,
    153. cname varchar,
    154. ename varchar,
    155. score numeric,
    156. rated numeric,
    157. instroduction text ,
    158. info text
    159. )
    160. ''' #创建数据表
    161. conn=sqlite3.connect(dbpath) #文件若存在就连接,不存在就连接
    162. cursor=conn.cursor() # 获取游标
    163. cursor.execute(sql)
    164. conn.commit()
    165. conn.close()
    166. if __name__=="__main__":
    167. #调用函数
    168. main()
    169. # init_db("movietest.db")
    170. print("爬取完毕!")