爬虫总结-数据解析与保存
二、解析数据
解析数据比较常用的库有re正则,bs4,xpath、pyquery、selector等
- bs4
Beautiful Soup是python的一个HTML或XML解析库,善于提取数据 , 自动将输入文档转换为Unicode编码,输出文档转换为UTF-8编码 ,在解析时依赖解析库,除了支持python标准库中的HTML解析器外,还支持一些第三方解析器(lxml、html5lib)
from bs4 import BeautifulSoup
import re
html = '''
<title>The Dormouse's story</title>
</head>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three title sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
string = '''
<div class="panel">
<div class="panel-heading">
<h4>hello</h4>
<div class="panel-body">
<ul class="list" id="list-1" name="elements">
<li class="element">Foo</li>
<li class="element">Bar</li>
<li class="element">Jay</li>
<ul class="list list-small" id="list-2">
<li class="element">Foo</li>
<li class="element">Bar</li>
<p>link 1</p>
# 1 基本用法
soup = BeautifulSoup(html, 'lxml') # BeautifulSoup对象初始化(自动更正格式),解析器为lxml
print(soup.prettify()) # prettify()方法将要解析的字符串以标准的缩进格式输出
print(soup.title.string) # 输出title节点的文本内容
# 2 节点选择器
# 选择元素
# 直接调用节点的名称就可以选择节点元素,再调用string属性就可以得到节点内的文本
soup = BeautifulSoup(html, 'lxml')
print(soup.title)
print(type(soup.title))
print(soup.title.string)
print(soup.head)
print(soup.p) # 选择第一个匹配到的节点,后面节点会忽略
# 3 提取信息
# 使用name属性获取节点的名称
soup = BeautifulSoup(html, 'lxml')
print(soup.title.name)
# 调用attrs获取所有属性
print(soup.p.attrs) # 返回一个包含属性和属性值的字典
# 获取单独属性
print(soup.p.attrs['name']) # 第一种方式相当于从字典中提取键值
print(soup.p['name']) # 直接在节点元素后面加中括号,传入属性名获取,因为是唯一属性,返回单个字符串
print(soup.p['class']) # 因为属性值不唯一,所以返回的是一个列表
# 获取内容
print(soup.p.string) # 利用string属性获取节点元素包含的文本内容
# 4 嵌套选择
soup = BeautifulSoup(html, 'lxml')
print(soup.head.title) # 嵌套调用选择节点
print(type(soup.head.title)) # 得到的结果依然是Tag类型
print(soup.head.title.string)
# 5 关联选择
html1 = '''
<title>The Dormouse's story</title>
</head>
<p class="story">
Once upon a time there were three title sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">
<span>Elsie</span>
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a>
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>
and they lived at the bottom of a well.
# 子节点与孙节点
soup = BeautifulSoup(html1, 'lxml')
print(soup.p.contents) # 调用contents属性获取节点元素的直接子节点,返回一个列表,
#其中每个元素都是p节点的直接子节点(不包含孙子节点)
print()
print(soup.p.children) # 调用children属性可以得到一样的结果,返回一个生成器
for i, child in enumerate(soup.p.children):
print(i)
print(child)
print(soup.p.descendants) # 递归查询,获取所有子孙节点
for i, child in enumerate(soup.p.descendants):
print(i)
print(child)
# 父节点和祖先节点
print(soup.a.parent) # 获取a节点的父节点
print(soup.p.parents) # 获取所有的祖先节点,返回结果是生成器类型
print()
print(list(enumerate(soup.p.parents)))
# 兄弟节点
print('next sibling', soup.a.next_sibling) # 下一个兄弟节点
print('prev sibling', soup.a.previous_sibling) # 上一个兄弟节点
print('next siblings', list(enumerate(soup.a.next_siblings))) # 后面的兄弟节点
print('prev siblings', list(enumerate(soup.a.previous_siblings))) # 前面的兄弟节点
# 6 方法选择器
# find_all(name, attrs, recursive, text, ***kwargs)——查询所有符合条件的元素
# name参数——节点名查询
soup = BeautifulSoup(string, 'lxml')
print(soup.find_all(name='ul')) # 传入name参数,查询所有ul节点,返回一个列表
print(type(soup.find_all(name='ul')[0])) # bs4.element.Tag类型
for ul in soup.find_all(name='ul'): # 进行嵌套查询
print(ul.find_all(name='li')) # 获取内部li节点
for li in ul.find_all(name='li'): # 遍历每个li
print(li.string) # 获取文本信息
# attrs参数——属性查询
print(soup.find_all(attrs={'id': 'list-1'})) # 传入的参数为字典类型,返回结果为列表
print(soup.find_all(attrs={'name': 'elements'}))
print(soup.find_all(id='list-1')) # 或者直接传入参数
print(soup.find_all(class_='element'))
# text参数——匹配节点文本,传入形式可以是字符串或者正则表达式对象
print(soup.find_all(text=re.compile('link')))
# find(name, attrs, recursive, text, ***kwargs)——查询第一个符合条件的元素
soup = BeautifulSoup(string, 'lxml')
print(soup.find(name='ul'))
print(type(soup.find(name='ul')))
# 7 CSS选择器
soup = BeautifulSoup(string, 'lxml')
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li')) # 选择ul节点下面的所有li节点
print(soup.select('#list-2 .element'))
print(type(soup.select('ul')[0]))
# 嵌套选择
for ul in soup.select('ul'):
print(ul.select('li'))
print(ul['id']) # 获取属性
# print(ul.attrs['id'])
# 获取文本
for li in soup.select('li'):
print('Get text:', li.get_text())
# print('String:', li.string)
- re
# 正则表达式的基本用法
import re
# 1 match()会从字符串的起始位置匹配正则表达式,一旦开头不匹配,那么整个匹配就失败,返回None
content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
# 第一个参数传入正则表达式,第二个参数传入了要匹配的字符串
result = re.match(r'^Hello\s\d{3}\s\d{4}\s\w{10}', content)
print(result)
print(result.group()) # group()方法输出匹配到的内容
print(result.span()) # span()方法输出匹配的范围
#2 匹配目标——从字符串中提取一部分内容
content = 'Hello 1234567 World_This is a Regex Demo'
# 使用()括号将想要提取的子字符串括起来,()实际上标记了一个子表达式的开始和结束位置,被标记的每个子表达式会依次对应每个分组
result = re.match(r'^Hello\s(\d+)\sWorld', content)
print(result)
print(result.group(), result.span())
print(result.group(1), result.span(1)) # 在group()方法中传入分组的索引即可获取提取的结果
# 3 通用匹配——.*
content = 'Hello 1234567 World_This is a Regex Demo'
# 万能匹配.*,.(点)可以匹配任意字符(除了换行符),*(星号)代表匹配前面的字符无限次,组合在一起可以匹配任意字符
result = re.match(r'^Hello.*Demo', content)
print(result)
print(result.group(), result.span())
# 4 贪婪与非贪婪
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match(r'^He.*(\d+).*Demo$', content) # 在贪婪模式下,.*会尽可能匹配多的字符
print(result)
print(result.group(1)) # .*的贪婪模式将123456匹配了,只给\d+留下一个可满足条件的数字7
result1 = re.match(r'He.*?(\d+).*Demo$', content) # 在.*后面加入?(问号),启用非贪婪匹配,尽可能匹配少的字符
print(result1)
print(result1.group(1)) # 在贪婪模式下,\d+可以匹配到1234567
# 5 修饰符
# 正则表达式可以包含一些可选标志修饰符来控制匹配的模式
content = "Hello 1234567 World_This \n is a Regex Demo"
result = re.match(r'^He.*?(\d+).*?Demo$', content, re.S) # re.S修饰符的作用是使.(点号)匹配包括换行符在内的所有字符
print(result.group(1))
# re.I 忽略大小写
# re.L 做本地化识别匹配
# re.M 多行匹配,影响^和$
# re.S 使.匹配包括换行符在内的所有字符
# re.U 根据Unicode字符集解析字符
# re.X 允许使用“#”引导注释
# 6 转义匹配
content = '(百度)www.baidu.com'
result = re.match('\(百度\)www\.baidu\.com', content) # 遇到特殊字符时,在前面加反斜线转义即可
print(result.group())
# 7 search()
# 匹配时扫描整个字符串,然后返回第一个成功匹配的结果(注意只返回第一个匹配结果)
html = '''<div id="songs-list">
<li data-view="7">
<a href="/2.mp2" singer="花粥">盗将行</a>
<li data-view="4" class="active">
<a href="/3.mp3" singer="银临">无题雪</a>
<li data-view="6"><a href="/4.mp3" singer="任然">离眸</a></li>
# 构建正则表达式对文本进行匹配,提取需要的字符;绝大多数HTML文本都包含了换行符,尽量都需要加上re.S修饰符
result = re.search(r'<li.*?active.*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:
print(result.group(1), result.group(2)) # 使用group()方法进行分组的提取
# 8 findall()
# 获取匹配正则表达式的所有内容
html = '''<div id="songs-list">
<li data-view="7">
<a href="/2.mp2" singer="花粥">盗将行</a>
<li data-view="4" class="active">
<a href="/3.mp3" singer="银临">无题雪</a>
<li data-view="6"><a href="/4.mp3" singer="任然">离眸</a></li>
results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
print(type(results), results) # 返回一个元组列表
for result in results:
print(result[0], result[1], result[2]) # 通过索引提取元组中的元素
# 9 sub()
# 使用正则表达式修改文本
content = "fdafa31fdaf12321qwd12312" # 去除文本中不需要的数字
# sub()方法接受三个参数,第一个参数为正则表达式,此处设置为\d+匹配所有数字;
# 第二个参数为替换成的字符串(如果为空表示去掉);第三个参数是匹配文本
result = re.sub(r'\d+', '', content)
print(result)
html = '''<div id="songs-list">
<li data-view="7">
<a href="/2.mp2" singer="花粥">盗将行</a>
<li data-view="4" class="active">
<a href="/3.mp3" singer="银临">无题雪</a>
<li data-view="6"><a href="/4.mp3" singer="任然">离眸</a></li>
html = re.sub(r'<a.*?>|</a>', '', html) # 使用sub()方法除去a节点,只保留文本
results = re.findall(r'<li.*?>(.*?)</li>', html, re.S) # 简化了findall()方法中需要使用的正则表达式
for result in results:
print(result.strip())
# 10 compile()
# 将正则表达式字符串编译成正则表达式对象,以便以后复用
content1 = '2016-12-15 12:00'
content2 = '2016-12-17 12:55'
content3 = '2016-12-22 13:21'
pattern = re.compile('\d{2}:\d{2}') # 封装正则表达式
result1 = re.sub(pattern, '', content1)
result2 = re.sub(pattern, '', content2)
result3 = re.sub(pattern, '', content3)
print(result1, result2, result3)
- xpath
# XPath,全称XML Path Language,即XML路径语言,是一门在XML文档中查找信息的语言
# 使用前需要安装lxml库
# XPath常用规则
# 表达式 描述
# nodename 选取此节点的所有子节点
# / 从当前节点选取直接子节点
# // 从当前节点选取子孙节点
# . 选取当前节点
# .. 选取当前节点的父节点
# @ 选取属性
# 例如:
# //title[@lang='eng']
# 选取所有名称为title,同时属性lang的值为eng的节点
from lxml.html import etree
# 1 XPath对网页的解析过程
text = '''
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
html = etree.HTML(text) # 构造一个XPath解析对象
result = etree.tostring(html) # 输出修正后的结果,类型为bytes
print(result.decode('utf-8')) # 转为str类型
# 2 读取文本文件进行解析
html = etree.parse('./text.html', etree.HTMLParser())
result = etree.tostring(html)
print(result.decode('utf-8'))
# 3 使用规则选取符合要求的节点
html = etree.parse('./text.html', etree.HTMLParser())
result = html.xpath('//*') # 使用//选取所有符合要求的节点,使用*匹配所有节点
result1 = html.xpath('//li') # 选取所有li节点
print(result) # 返回一个列表,其中的每个元素为Element类型,显示节点名称
print(result1)
# 4 查找子节点、子孙节点及父节点
html = etree.parse('./text.html', etree.HTMLParser())
result = html.xpath('//li/a') # 使用/查找当前节点的子节点
result1 = html.xpath('//li//a') # 使用//查找当前节点的子孙节点
result2 = html.xpath('//a[@href="link4.html"]/../@class') # 使用..查找当前节点的父节点
# result2 = html.xpath('//a[@href="link4.html"]/parent::*/@class') # 也可以使用parent::获取父节点
print(result)
print(result1)
print(result2)
# 5 属性匹配与属性获取
html = etree.parse('./text.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]') # 使用[]和@符号匹配属性,此处限定节点的class属性为"item-0"
result1 = html.xpath('//li/a/@href') # 单独获取节点属性直接使用@,返回属性值列表
print(result)
print(result1)
# 6 节点文本获取——text()方法
html = etree.parse('./text.html', etree.HTMLParser())
result = html.xpath('//li[@class="item-0"]/a/text()') # <a>节点是<li>的子节点,要想获取<li>节点内部的文本,可以逐层选取
result1 = html.xpath('//li[@class="item-0"]//text()') # 直接使用//选取<li>节点的所有子孙节点,返回三个结果,前两个是<a>节点内部的文本,第三个是最后一个<li>节点内部的文本,即换行符
print(result)
print(result1)
# 7 属性多值匹配——某个属性可能有多个值
text = '''
<li class="li li-first"><a href="link.html">first item</a></li>
html = etree.HTML(text) # 文本中class属性有两个值li和li-first
result = html.xpath('//li[contains(@class, "li")]/a/text()') # 使用contains()方法,第一个参数传入属性名,第二个参数传入属性值
print(result)
# 8 多属性匹配——节点有多个属性
text = '''
<li class="li li-first" name="item"><a href="link.html">first item</a></li>
html = etree.HTML(text)
result = html.xpath('//li[contains(@class, "li") and @name="item"]/a/text()') # 使用运算符and连接多个属性
print(result)
# 9 按序选择——选择某个节点
html = etree.parse('./text.html', etree.HTMLParser())
result = html.xpath('//li[1]/a/text()') # 第一个节点
print(result)
result = html.xpath('//li[last()]/a/text()') # 最后一个节点
print(result)
result = html.xpath('//li[position()<3]/a/text()') # 位置小于3的节点,即第一个、第二个节点
print(result)
result = html.xpath('//li[last()-2]/a/text()') # 倒数第三个节点,last()是倒数第一,last()-2即倒数第三个
print(result)
# 10 节点轴选择
# XPath提供了很多节点轴选择方法,包括获取子元素、兄弟元素、父元素、祖先元素等
text = '''
<li class="item-0"><a href="link1.html"><span>first item</span></a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
html = etree.HTML(text)
result = html.xpath('//li[1]/ancestor::*') # 调用ancestor轴,可以获取所有祖先节点,其后需要跟两个冒号::
print(result)
result = html.xpath('//li[1]/ancestor::div') # 在冒号后面加div,限定祖先节点为div
print(result)
result = html.xpath('//li[1]/attribute::*') # 调用attribute轴,可以获取所有属性值
print(result)
result = html.xpath('//li[1]/child::a[@href="link1.html"]') # 调用child轴,可以获取所有直接子节点,后面接了限定条件
print(result)
result = html.xpath('//li[1]/descendant::span') # 调用descendant轴,获取所有子孙节点,限定条件为span
print(result)
result = html.xpath('//li[1]/following::*[2]') # 调用following轴,可以获取当前节点之后的所有节点,使用索引[2]获取第二个后续节点
print(result)
result = html.xpath('//li[1]/following-sibling::*') # 调用following-sibling轴,可以获取当前节点之后的所有同级节点
print(result)
- pyquery
基于css选择器
from pyquery import PyQuery as pq
html = '''
<div id="container">
<ul class="list">
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
# 1 初始化:需要传入HTML文本来初始化一个PyQuery对象
# 字符串初始化
doc = pq(html) # 初始化一个PyQuery对象
print(doc('li')) # 再传入CSS选择器
# url初始化
doc = pq(url='https://cuiqingcai.com')
print(doc('title'))
# 文件初始化
# doc = pq(filename='demo.html')
# 2 基本CSS选择器
doc = pq(html)
# 先选取id为container的节点,再选择其内部的class为list的节点内部的所有li节点
print(doc('#container .list li'))
print(type(doc('#container .list li')))
# 3 查找节点
# 查找子节点——find()方法
doc = pq(html)
items = doc('.list') # 选取class为list的节点
print(type(items))
print(items)
lis = items.find('li') # 选取内部的li节点
print(type(lis))
print(lis)
# 查找父节点——parent()方法
parent = items.parent()
print(parent)
print()
# 查找祖先节点——parents()方法
parents = items.parents()
print(parents)
print()
# 查找兄弟节点——siblings()方法
li = doc('.list .item-0.active') # 首先选择class为list的节点内部class为item-0和active的节点
print(li.siblings()) # 找出它的兄弟节点
print(li.siblings('.active')) # 传入css选择器,筛选特定的节点
# 4 遍历
# 对于多个节点的结果,需要遍历获取
doc = pq(html)
lis = doc('li').items() # 调用items()方法,获得一个生成器
print(type(lis))
for li in lis:
print(li, type(li))
# 5 获取信息
# 获取属性
doc = pq(html)
a = doc('.item-0.active a')
print(a, type(a))
print(a.attr('href')) # 使用attr()方法获取属性
print(a.attr.href) # 也可以通过调用attr属性来获取
print()
a = doc('a')
for item in a.items():
print(item.attr('href'))
print()
# 获取文本
doc = pq(html)
a = doc('.item-0.active a')
print(a)
# 调用text()方法获取内部文本信息,忽略节点内部包含的所有HTML,只返回纯文字内容;如果是多个节点不需要遍历
print(a.text())
print(a.html()) # 调用html()方法获取节点内部的HTML文本;如果是多个节点需要遍历
# 6 节点操作
# addClass 和 removeClass——动态改变节点的class属性
doc = pq(html)
li = doc('.item-0.active')
print(li)
li.remove_class('active') # 移除active这个class
print(li)
li.add_class('active') # 添加active这个class
print(li)
# attr、text和html
li.attr('name', 'link') # 如果传入一个参数就是获取属性值,传入两个参数可以修改属性
print(li)
li.text('changed item') # 如果传入参数就会改变节点内部内容
print(li)
li.html('<span>changed item</span>') # 如果传入参数就会改变节点内部内容
print(li)
# remove()
string = '''
<div class="wrap">
Hello world
<p>This is a paragraph.</p>
doc = pq(string) # 只需要提取Hello world
print(doc('.wrap').text()) # 但是text()方法会获取所有纯文本内容组合成一个字符串
wrap = doc('.wrap')
wrap.find('p').remove() # 选中p节点,调用remove()方法移除
print(wrap.text())
# 7 伪类选择器
doc = pq(html)
li = doc('li:first-child') # 第一个节点
print(li)
li = doc('li:last-child') # 最后一个节点
print(li)
li = doc('li:nth-child(2)') # 第二个节点
print(li)
li = doc('li:gt(2)') # 第三个li后的节点(0为第一个节点)
print(li)
li = doc('li:nth-child(2n)') # 偶数位置节点
print(li)
li = doc('li:contains(second)') # 包含second文本的节点
print(li)
三、保存数据
数据可以保存到文本文档、csv,xlxs、数据库等
- 文本文档
url = 'https://www.zhihu.com/explore'
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
html = requests.get(url, headers=headers).text # 获取网站源代码
doc = pq(html)
items = doc('.explore-tab .feed-item').items() # 解析库解析,使用items()方法遍历获取多个节点
for item in items:
question = item.find('h2').text()
author = item.find('.author-link-line').text()
answer = pq(item.find('.content').html()).text()
with open('explore.txt', 'a', encoding='utf-8') as f:
f.write('\n'.join([question, author, answer]))
f.write('\n' + '=' * 50 + '\n')
- csv
with open('data.csv', 'w', newline='') as f: # 加入newline参数,解决写入一行数据后会有空行的问题
writer = csv.writer(f, delimiter=' ') # writer()方法初始化写入对象,传入delimiter参数修改列与列之间的分割符
writer.writerow(['id', 'name', 'age']) # writerow()方法传入一行的数据
writer.writerow(['10001', 'Mike', 20])
writer.writerow(['10002', 'Bob', 22])
writer.writerow(['10003', 'Jordon', 21])
# writer.writerows([['10001', 'Mike', 20], ['10002', 'Bob', 22], ['10003', 'Jordon', 21]]) # 调用writerows()方法同时写入多行,此处参数需要为二维列表
- json
# 1 读取JSON
string = '''
"name": "Bob",
"gender": "male",
"birthday": "1992-10-18"
"name": "Selina",
"gender": "female",
"birthday": "1995-10-18"
print(type(string))
data = json.loads(string) # loads()方法将字符串转为JSON对象
print(data)
print(type(data))
print(data[0]['name']) # 通过使用索引获取对应内容
print(data[0].get('name')) # 使用get()方法传入键名,如果键名不存在,则不会报错,会返回None;支持传入第二个参数——默认值。
# 2 输出JSON
data = [{
"name": "Bob",
"gender": "male",
"birthday": "1992-10-18"
with open('data.json', 'w') as f:
f.write(json.dumps(data, indent=2)) # 使用dumps()方法将JSON对象转化为字符串,写入文本;参数indent表示缩进字符个数,传入该参数可以保存JSON的格式
data1 = [{
"name": "王伟",
"gender": "男",
"birthday": "1992-10-18"
with open('data.json', 'w', encoding='utf-8') as f: # 规定文件输出编码为utf-8
f.write(json.dumps(data1, indent=2, ensure_ascii=False)) # 指定参数ensure_ascii为False,可以输出中文
- 字典写入
with open('data.csv', 'a', newline='') as f:
filenames = ['id', 'name', 'age'] # 定义三个字段
writer = csv.DictWriter(f, fieldnames=filenames) # 初始化字典写入对象
writer.writeheader() # 写入头信息
writer.writerow({'id': '10001', 'name': 'Mike', 'age': 20})
writer.writerow({'id': '10002', 'name': 'Bob', 'age': 22})
writer.writerow({'id': '10003', 'name': 'Jordon', 'age': 21})
- mysql数据库
import pymysql
import traceback
class MySql:
def __init__(self):
self.conn = self.to_connect()
self.is_connected()
self.cursor = self.conn.cursor()
def __del__(self):
self.conn.close()
def to_connect(self):
return pymysql.connect(host='127.0.0.1', user='root', password='root', database='myself', charset='utf8')
def is_connected(self):
"""Check if the server is alive"""
self.conn.ping(reconnect=True)
print("db is connecting")
except:
traceback.print_exc()
self.conn = self.to_connect()
print("db reconnect")
def Excute(self, sql):
self.cursor.execute(sql)
self.conn.commit()
except Exception as e:
self.conn.rollback()
with open('MySql.sql', 'a') as f:
f.write(sql)
print(str(e))
def Close(self):
self.cursor.close()
self.conn.close()
- MongoDB
import pymongo
# 1 数据库连接
client = pymongo.MongoClient(host='localhost', port=27017) # 传入地址和端口
# client = pymongo.MongoClient('mongodb://localhost:27017/') # 或者传入连接字符串
# 指定数据库
db = client.test
# db = client['test'] # 调用test属性也可以返回test数据库
# 指定集合
# MongoDB数据库包含许多集合,他们类似于关系型数据库中的表
collection = db.students # 指定一个集合名称为students
# 2 插入数据
student = {
'id': '20170101',
'name': 'Jordan',
'age': 20,
'gender': 'male'
result = collection.insert_one(student) # 调用insert_one()方法插入数据
print(result.inserted_id) # 每条数据都有_id属性来唯一标识,如果不显示指明,则自动产生。
student1 = {
'id': '20170101',
'name': 'Jordan',
'age': 20,
'gender': 'male'
student2 = {
'id': '20170202',
'name': 'Mike',
'age': 21,
'gender': 'male'
result = collection.insert_many([student1, student2]) # 调用insert_many()方法插入多条数据
print(result.inserted_ids)
# 3 查询数据
query = collection.find_one({'name': 'Mike'}) # 单条数据查询,返回一个生成器对象
print(type(query))
print(query)
querys = collection.find({'age': 20}) # 多条数据查询,返回生成器
print(querys)
for i in querys: # 遍历获取结果
print(i)
# 条件查询——使用比较符号
# 符号 含义 示例
# $lt 小于 {'age': {'$lt': 20}}
# $gt 大于 {'age': {'$gt': 20}}
# $lte 小于等于 {'age': {'$lte': 20}}
# $gte 小于等于 {'age': {'$gte': 20}}
# $ne 不等于 {'age': {'$ne': 20}}
# $in 在范围内 {'age': {'$in': [20, 30]}}
# $nin 不在范围内 {'age': {'$nin': [20, 30]}}
# 查询年龄大于20的数据
querys = collection.find({'age': {'$gt': 20}}) # 查询的条件键值是一个字典,其键名为比较符号$gt,意为大于,键值为20
for i in querys:
print(i)
# 功能查询——使用功能符号
# 符号 含义 示例 示例含义
# $regex 匹配正则表达式 {'name': {'$regex': '^M.*'}} name以M开头
# $exists 属性是否存在 {'name': {'$exists': True}} name属性存在
# $type 类型判断 {'age': {'$type': 'int'}} age的类型为int
# $mod 数字模操作 {'age': {'$mod': [5, 0]}} age模5余0
# $text 文本查询 {'$text': {'$search': 'Mike'}} text类型的属性中包含Mike字符串
# $where 高级条件查询 {'$where': 'obj.fans_count==obj.follows_count'} 自身粉丝数等于关注数
# 查询名字以M开头的学生数据
querys = collection.find({'name': {'$regex': '^M.*'}})
print()
for i in querys:
print(i)
# 4 计数——统计查询结果有多少条数据
count = collection.find().count() # 统计所有数据
print(count)
count = collection.count_documents({'age': 20}) # 统计符合条件数据
print(count)
# 5 排序
results = collection.find().sort('name', pymongo.ASCENDING) # 指定升序,降序使用DESCENDING
print([result['name'] for result in results])
# 6 偏移
results = collection.find().sort('name', pymongo.ASCENDING).skip(2).limit(2) # 偏移两个位置,就忽略了前两个元素,得到第三个及以后的元素,使用limit(2)限制获取两个元素
print([result['name'] for result in results])
# 7 更新
condition = {'name': 'Mike'} # 指定查询条件
student = collection.find(condition) # 查询数据
result = collection.update_one(condition, {'$set': student}) # 更新数据,需要使用$set类型操作符作为键名
# result = collection.update_many(condition, {'$set': {'age': 26}}) # 更新多条数据
print(result)
print(result.matched_count, result.modified_count) # 获取匹配的数据条数和影响的数据条数
# 8 删除
result = collection.delete_one({'name': 'Kevin'}) # 删除一条数据
print(result)
print(result.deleted_count) # 获取删除的数据条数
result = collection.delete_many({'age': {'$lt': 25}}) # 删除所有符合条件的数据