Python爬虫

视频资源来自:b站——Python爬虫编程基础5天速成P15-P28
文章仅为个人观看视频后的学习心得笔记,用于个人查看和记录保存。文中定有疏漏错误之处,恳请指正。

Python爬虫

任务介绍

百度指数,可以看搜索量数据哈哈哈哈

爬虫知识

基本流程

准备工作

1.分析页面

Headers

image-20210801212912185

2.编码规范

一般Python程序第一行需要加入
#-*-coding:utf-8 -*-或者# coding=utf-8。这样代码可以包含中文

Python文件中可以加入main函数用于测试程序。(程序入口)

if __name__ == "__main__" :

3.引入模块

moudule 模块,package包。包是含有Python模块的文件夹,为了防止模块名冲突,python引入的按目录组织模块的方法

from test1 import t1

从包test1里导入模块t1

Settings -> Project [myProject] ->Project Interpreter 解释器 里保存了很多 第三方包

安装:pip install bs4
也可以在解释器设置里点+搜索安装

from bs4 import BeautifulSoup     #网页解析,获取数据
import re       #正则表达式,进行文字匹配
import urllib.request,urllib.error #指定URL,获取网页数据
import xlwt     #进行excel操作
import sqlite3  #进行SQLite数据库操作
def main():
    baseurl = 'https://movie.douban.com/top250'
    #1爬取网页
    datalist = getData(baseurl)
    savePath = r".\豆瓣电影Top250.xls"
    #3.保存数据
    saveData(savePath)

获取数据

补充:head

用户代理,标识告诉豆瓣服务器,我们是什么类型的机器、浏览器(本质上是告诉服务器,我们可以接收什么水平的文件内容)

# 爬取网页
def getData(baseurl):
  datalist = []
  for i in range(0, 250, 25):  # 调用获取页面信息的函数,一共250条,一页25条。(所以一共10次)
    url = baseurl + str(i)
    html = askURL(url)  # 保存获取到的网页源码
  # 2逐一解析数据
  return datalist


# 得到指定一个URL的网页内容
def askURL(url):
  # 模拟浏览器头部信息,向豆瓣服务器发送消息
  head = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
  }
  # 用户代理,标识告诉豆瓣服务器,我们是什么类型的机器、浏览器(本质上是告诉服务器,我们可以接收什么水平的文件内容)

  request = urllib.request.Request(url, headers=head)
  html = ""
  try:
    response = urllib.request.urlopen(request)
    html = response.read().decode("utf-8")
    print(html)
  except urllib.error.URLError as e:
    if hasattr(e, 'code'):
      print(e.code)
    if hasattr(e, "reason"):
      print(e.reason)
  # return html

解析内容

补充:
BeautifulSoup
正则表达式

image-20210802191715360

正则表达式<a href="(.*?)">
.*?非贪婪匹配。表示重复任意次,但是尽可能的少重复。否则后面的">也会被匹配进去

link = re.findall(re.compile(r'<a href="(.*?)">'),item)[0]

这里正则表达式里加了括号。括号里的内容是最终匹配输出的 链接。如果把括号去掉,那么<a 标签 什么的都会显示出来。如果这里有2对括号,那么结果就是有2个值的列表。

findLink = re.compile(r'<a href="(.*?)">')
findImgSrc = re.compile(r'<img.*src="(.*?)"',re.S)
findTitle = re.compile(r'<span class="title">(.*?)</span>')
findScore = re.compile(r'<span class="rating_num" property="v:average">(.*?)</span>')
findJudge = re.compile(r'<span>(\d*?)人评价</span>')
findInq = re.compile(r'<span class="inq">(.*?)</span>')
findBd = re.compile(r'<p class="">(.*?)</p>',re.S)

re.S让换行符包含在字符中

保存数据

Excel保存(xlwt)

write(行,列,内容)

写入九九乘法表数据

import xlwt
workbook = xlwt.Workbook(encoding='utf-8')#创建workbook对象
worksheet = workbook.add_sheet('sheet1')#创建工作表
#worksheet.write(0,0,'hello')#写入数据:行,列,内容
for i in range(9):
  for j in range(i+1):
    worksheet.write(i,j,f'{j+1}*{i+1}={(i + 1) * (j + 1)}')
workbook.save('student.xls')

实例:

def saveData(savepath,datalist):
  book = xlwt.Workbook(encoding='utf-8',style_compression=0)  #样式压缩
  sheet = book.add_sheet('豆瓣电影Top250',cell_overwrite_ok=True) #可以覆盖单元格
  col = ('电影详情链接','图片链接','影片中文名','影片外国名','评分','评价数','概况','相关信息')
  # worksheet.write(0,0,'hello')#写入数据:行,列,内容
  for i in range(8):
    sheet.write(0,i,col[i])
  for i in range(250):
    print(f'正在保存第{i+1}条')
    data = datalist[i]
    for j in range(8):
      sheet.write(i+1,j,data[j])
  book.save('豆瓣电影Top250.xls')

SQL保存(sqlite3)

补充:sqlite3

初始化数据库,建表:

def init_db(dbpath):
  sql = '''
      create table movie250
      (
      id integer  primary key autoincrement,
      info_link text,
      pic_link text,
      cname varchar,
      ename varchar,
      score numeric,
      rated numeric ,
      instroduction text,
      info text
      )
  '''
  conn = sqlite3.connect(dbpath)
  cursor = conn.cursor()
  cursor.execute(sql)
  conn.commit()
  conn.close()

写入数据:

def saveDataDB(dbpath,datalist):

  init_db(dbpath)
  conn = sqlite3.connect(dbpath)
  cur = conn.cursor()
  for data in datalist:
    for index in range(len(data)):
      if index == 4 or index == 5:
        continue
      data[index] = '"'+data[index]+'"'
    sql ='''
      insert into movie250 (info_link,pic_link,cname,ename,score,rated,instroduction,info)
      values(%s)''' % ",".join(data)
    print(sql)
    cur.execute(sql)
    conn.commit()
  cur.close()
  conn.close()

补充内容

head

import urllib.request
#获取一个get请求
response=urllib.request.urlopen("http://www.baidu.com")
print(response.read().decode("utf-8")) #对获取到的网页源码进行utf-8的解码

response、response.read()、response.read().decode("utf-8")

image-20210802104314320

get请求:

image-20210802112736614

这里User-Agent 就告诉浏览器自己是爬虫。(不然就会给一些浏览器信息)

import urllib.request
import urllib.parse
#获取一个post请求
data = bytes(urllib.parse.urlencode({"hello":"world"}),encoding="utf-8")
response = urllib.request.urlopen('http://httpbin.org/post',data=data)
print(response.read().decode("utf-8"))

超时处理:

try:
  response = urllib.request.urlopen('http://httpbin.org/get',timeout=0.01)
  print(response.read().decode("utf-8"))
except urllib.error.URLError as e:
  print('time out!')

服务器返回错误码:418。拒绝访问请求!我是一个茶壶!
啊~被发现是爬虫了

response = urllib.request.urlopen('http://www.baidu.com/')
print(response.status)
print(response.getheaders())
print(response.getheader("Server"))
image-20210802143431829

随便找个网页,找到包里的user-agent。这就是我们真实的浏览器信息!!骗过服务器。要是整个包都复制下来封装好,发过去,那就是真实的浏览器请求!!

豆瓣的访问:

url = "https://www.douban.com"
headers = {
  "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
}
req = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(req)
print(response.read().decode("utf-8"))

User-Agent必须一模一样!不然就伪装失败

BeautifulSoup

BeautifulSoup4将复杂html文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
Tag、NavigableString、BeautifulSoup、Comment

BeautifulSoup(html,'html.parser')

用BeautifulSoup解析一个html(变量)的文件。使用的解析器叫html.parser

from bs4 import BeautifulSoup
file = open("./baidu.html",'rb')
html = file.read()
bs = BeautifulSoup(html,'html.parser')
print(bs.title)
print(bs.a)
image-20210802160331720

Tag:拿到它所找到的第一个标签+内容

print(bs.title.string)
print(bs.a.attrs)

获取内容、获取属性
输出:
百度一下,你就知道
{'class': ['mnav'], 'href': 'http://news.baidu.com', 'name': 'tj_trnews'}

comment是一个特殊的NavigableString,输出的内容不包含注释符号

文档的遍历

print(bs.head.contents):返回一个列表,包含了head里面的东西们

image-20210802162909623

字符串过滤:会查找与字符串完全匹配的内容。
所有的a标签↓加了limit之后,就只显示前3个。

t_list = bs.find_all('a')
t_list = bs.find_all('a',limit=3)

正则表达式搜索:使用search()方法来匹配内容
所有标签里有a的↓

import re
t_list = bs.find_all(re.compile("a"))

方法:传入一个函数(方法),根据函数的要求来搜索(了解)

def name_is_exists(tag):
  return tag.has_attr('name')
t_list = bs.find_all(name_is_exists)

kwargs:

t_list = bs.find_all(id="head")
t_list = bs.find_all(class_=True)

参数值↑

text参数:

t_list = bs.find_all(text=["hao123","地图","贴吧"])
t_list = bs.find_all(text= re.compile("\d"))

可以用列表,也可以用正则表达式

limit参数

css选择器:

t_list = bs.select('title')#通过标签来查找
t_list = bs.select('.mnav')#通过类名查找
t_list = bs.select('#u1')#通过id查找
t_list = bs.select('a[class=“bri”]')#通过属性查找
t_list = bs.select('head > title')#通过子标签来查找
t_list = bs.select('.mnav ~ .bri')#通过兄弟类来查找。(和mnav是兄弟,且类为bri的标签)

re正则表达式

image-20210802173730641
image-20210802174408805
image-20210802174612670

正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。
多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

re.compile()创建正则表达式对象,表示规则(字符串的模式)

import re
pat = re.compile("AA") #正则表达式
m = pat.search("ABCAA")  #search字符串被校验的内容

m = re.search("AA","AbCAA")#简单写法↑

search进行比对查找。就找到第一个

m = re.findall("AA","AABCAA")
m = re.findall("[A-Z]+","ASDaFPGAa")#['ASD', 'FPGA']

findall找到所有的。

sub
re.sub('a','A','abcdefgcasd') 找到a,用A替换

建议在正则表达式中,被比较的字符串前面加上r,不用担心转义字符的问题

sqlite3

社区版(已放弃尝试)

安装插件 database navigator。就可以看db文件啦!
打开db Browser,新建数据库。将自己的db文件代替sqlite.db。
单击Test Connection。

如果提示:
Invalid or incomplete database configuration:
- Database information incomplete or invalid (host, port, database, file)

是因为点击添加,在新的一行输入路径

解决:直接将第一行的sqlite.db修改为数据库文件路径

image-20210802224937876

添加完之后,点Apply,下载资源!

import sqlite3

conn = sqlite3.connect('test.db')#打开/创建
# print('Opened database successfully')
print("成功打开数据库")
c = conn.cursor()#获取游标
sql = '''
  create table company
  (id int primary key not null,
  name text not null,
  address char(50),
  salary real);
'''
c.execute(sql)  #执行sql语句
conn.commit() #提交数据库操作
conn.close()
print("成功建表")
image-20210802225941961

建完表之后刷新

专业版

image-20210803141048766

建立表

import sqlite3

conn = sqlite3.connect('test.db')#打开/创建
# print('Opened database successfully')
print("成功打开数据库")
c = conn.cursor()#获取游标
sql = '''
  create table company
    (id int primary key not null,
    name text not null,
    age int not null,
    address char(50),
    salary real);
'''
c.execute(sql)  #执行sql语句
conn.commit() #提交数据库操作
conn.close()
print("成功建表")

插入数据:
把sql换成

sql = '''
   insert into company(id,name,age,address,salary)
   values (1,'张三',32,'成都',8000),
   (2,'李四',40,'北京',20000);
'''

查询数据:

import sqlite3

conn = sqlite3.connect('test.db')#打开/创建
print("成功打开数据库")
c = conn.cursor()#获取游标
sql='''
   select id,name,address,salary from company
'''
cursor = c.execute(sql)
for row in cursor:
    print('id=',row[0],'name=',row[1],'address=',row[2])
conn.close()
image-20210803154710543

右键表格,编辑源码,可以测试sql语句

其它个人笔记

json.loads():把json文件转成字典格式。

data = json.loads(srcData)

B站,个人主页。可以爬取所有投稿信息:
https://api.bilibili.com/x/space/arc/search?mid=【作者id】&ps=30&tid=0&pn=【页数】&keyword=&order=pubdate&jsonp=jsonp

B站,视频播放页。可以爬取评论信息:
https://api.bilibili.com/x/v2/reply/main?jsonp=jsonp&next=0&type=1&oid=【aid,av号】&mode=3&plat=1&_=

excel异步保存,追加数据

参考Python3读取、写入、追加写入Excel文件

import xlwt  # 读取
import xlrd     #写入
from xlutils.copy import copy

文件头我用另一个函数初始化了。

def saveData(savepath,datalist):
  book = xlrd.open_workbook(savepath)
  sheets = book.sheet_names()  # 获取工作簿中的所有表格
  worksheet = book.sheet_by_name(sheets[0])  # 获取工作簿中所有表格中的的第一个表格
  rows_old = worksheet.nrows
  new_workbook = copy(book)  # 将xlrd对象拷贝转化为xlwt对象
  new_worksheet = new_workbook.get_sheet(0)
  for index in range(len(datalist)):
    print(f'正在保存第{index+rows_old}条')
    data = datalist[index]
    print(data)
    for p in range(len(data)):
      new_worksheet.write(index+rows_old,p,data[p])
  new_workbook.save(savepath)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348

推荐阅读更多精彩内容