文章目录
一:爬虫基本原理
爬虫就是获取网页并提取和保存信息的自动化程序
如果把互联网比喻为一张大网,那么每个网页就是这张大网的一个节点,网页与网页之间的链接就相当于节点之间的连线,爬虫每到一个节点就获取他的信息,然后通过连线爬到另一个节点,这样整个网的所有节点的数据就都可以被爬取下来了。
爬虫的自动化的操作流程(灵魂所在)
- 发送HTTP请求获取网页源码
- 从返回的网页的源码种提取信息
- 把提取到的信息保存起来
在提取信息的过程中,可能经常会用到正则表达式获取信息
二. 爬虫基本操作
1.发送请求
使用requests
库进行发送请求的操作,简单易上手
文档连接如下:
中文文档
官网中文版
1.1 demo:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)\
Chrome/80.0.3987.106 Safari/537.36'
}
r = requests.get('http://maoyan.com/board/4', headers=headers)
if r.status_code == 200:
print(r.text)
很多网站如果我们不提供user-agent
的话是不让爬的,so
1.2 如何查看自己user-agent?
Chrome:在浏览器的搜索框中输入about:version
即可
其他任何浏览器运行这段脚本就行了:
(复制下面代码到新建的空html文件中,选择你要的浏览器运行)
<html>
<head>
<script>
window.onload(alert(navigator.userAgent))
</script>
</head>
</html>
2.提取信息
发送完请求并且成功获取到了网页源码后,需要提取我们需要的信息,正则表达式是非常常见的方法
2.1 正则表达式常用规则
表达式 | 含义 |
---|---|
\w | 匹配字母、数字、下划线 |
\W | 匹配不是字母、数字、下划线的字符 |
\s | 匹配任意空白字符,等价于 [\t\n\r\f] |
\S | 匹配任意非空白字符 |
\d | 匹配任意数字、等价于 [0-9] |
\D | 匹配任意非数字的字符 |
\A | 匹配字符串开头 |
\Z | 匹配字符串结尾,如果存在换行,只匹配到换行前的结束字符串 |
\z | 匹配字符串结尾,如果存在换行,同时还会匹配换行符 |
\G | 匹配最后匹配完成的位置 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
^ | 匹配一行字符串的开头 |
$ | 匹配一行字符串的结尾 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符 |
[ … ] | 用来表示一组字符,单独列出,比如[abc]匹配a、b或c |
[ ^… ] | 匹配不在[]中的字符,比如[ ^abc ]则匹配a,b,c以外的字符 |
* | 匹配0或多个表达式,贪婪型 |
+ | 匹配1个或多个表达式,贪婪型 |
? | 陪陪0个或1个表达式,非贪婪型 |
{n} | 精确匹配n个前面的表达式,非贪婪型 |
{n,m} | 匹配n到m次前面的表达式,贪婪型 |
a|b | 匹配a或b |
() | 匹配括号内的表达式,表示一个组 |
2.2 正则表达式常用方法
compile()
match()
search()
findall()
sub()
每次根据源码编写我们的正则表达式模板就显得很繁琐,不够优美。那么一套用来解析源码轻而易举获取我们所需信息的工具就很有必要了。
2.3 解析库介绍1:Beautiful Soup
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag , NavigableString , BeautifulSoup , Comment.
船新包装,船新体验
官方中文文档
Beautiful Soup在解析时实际上会依赖解析器:
根据需要选择
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup, "html.parser") | Python的内置标准库,执行速度适中,文档容错能力强 | Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差 |
lxml HTML 解析器 | BeautifulSoup(markup, "lxml") | 速度快,文档容错能力强 | 需要安装C语言库 |
lxml XML 解析器 | BeautifulSoup(markup, ["lxml-xml"]) BeautifulSoup(markup, "xml") | 速度快,唯一支持XML的解析器 | 需要安装C语言库 |
html5lib | BeautifulSoup(markup, "html5lib") | 最好的容错性,以浏览器的方式解析文档,生成HTML5格式的文档 | 速度慢,不依赖外部扩展 |
如果你觉得Beautiful Soup还是有些麻烦或者不习惯
2.4 解析库介绍2:PyQuery
它与JQuery的语法非常相似,CSS选择器对于写过前端的朋友来说简直不要太好用
轻松上手,纵享丝滑
官方文档
初始化
from pyquery import PyQuery as pq
- html字符串初始化
doc = pq(html)
- URL初始化
doc = pq('https://baidu.com')
- 文件初始化
doc = pq(filename='doc.html')
CSS选择器
doc = pq(html)
doc('#container ul li')
#获取id=container节点下的li节点
节点查找
- 子节点
find()
、children()
- 父节点
parent()
- 兄弟节点
siblings()
遍历
items()
信息获取
- 属性
attr()
- 文本
text()
、html()
具体用法详情可以看官方文档
3.数据存储
#已获取信息result
with open("result.txt", 'a', encoding='utf-8') as f:
f.write(result)
这么做也能保存数据,但是不够炫酷。
3.1 JSON形式保存
JSON全称JavaScripte Object Notation(JavaScript的对象标记),它通过对象数组来表示数据,构造简洁,结构化程度高,是一种轻量级的数据交换格式。
- 对象:
JavaScript中,用{}
括起来的内容表示对象,与python中的字典写法很像,其结构为{ key0: value0, key1: value1 }
- 数组
JavaScript中,用[]
括起来的部分表示数组,与python中的列表写法很像,其结构为['value0', 'value1']
综上,JSON数据格式为:
[
{
"name": "Bob",
"age": "12"
},
{
"name": "Tom",
"age": "11"
}
]
JSON的数据要用双引号包围,不能使用单引号,不然解析时会出问题
JSON解析的过程就是将字符串转为JSON对象,反之亦然。
用load()
和dumps()
方法可以轻松实现数据转换
J S O N 文 本 l o a d s ( ) → J S O N 对 象 JSON文本 \hspace2ex \underrightarrow{loads()} \hspace2ex JSON对象 JSON文本loads()JSON对象
J
S
O
N
文
本
d
u
m
p
s
(
)
←
J
S
O
N
对
象
JSON文本 \hspace2ex \underleftarrow{dumps()} \hspace2ex JSON对象
JSON文本dumps()JSON对象
3.2 CSV形式保存
CSV,全称为Comma-Separated Values,中文可以叫做逗号分隔值或字符分隔值,其文件以纯文本的形式处理表格数据。
文件格式如下
num1, num2, num3
1,2,3
a,b,c
写csv文件:
import csv
with open('data.csv', 'w') as csvfile:
filenames = ['id', 'name', 'age']
writer = csv.DictWriter(csvfile, fieldnames=filenames)
writer.writerow('id':'11001','name':'Bob', 'age': '10')
writer.writerow('id':'11002','name':'Tim', 'age': '10')
writer.writerow('id':'11003','name':'Mike', 'age': '10')
或者:
import csv
with open('data.csv', 'w') as csvfile:
writer = csv.Writer(csvfile)
writer.writerow('id', 'name', 'age')
writer.writerow('11001','Bob','10')
writer.writerow('11002','Tim','10')
writer.writerow('11003','Mike','10')
效果是一样的
读csv文件:
import csv
with open('data.csv', w) as csvfile:
reader = csv.reader(csvfile)
for row in reader:
print(row)
3.2 关系型数据库MySQL保存
关系型数据库是基于数据模型之关系模型的一种数据库,区别于层次数据库和网状数据库。关系数据库通过表来存储数据,表的每一列称为一个字段,对应一个域,表示实体的某一属性,表的每一行称为一条记录,对应一个元组,是某一实体分量的集合。不同的表之间通过主键和外键进行关联,多表关联组成关系型数据库。
有关python连接mysql以及CRUD
操作:
import pymysql
#连接数据库
db = pymysql.connect(host='localhost',user='root',
password='123456',port=3306,db='spider')
cursor = db.cursor()
#增
sql0 = 'INSERT INTO table(column0,column1,column2) values(%s, %s, %s)'#此类
#删
sql1 = 'DELETE FROM table WHERE condition'#此类
#查
sql2 = 'SELECT * FROM table WHERE age >= 20'#此类
#改
sql3 = 'UPDATE table SET column = %s WHERE condition'#此类
try:
cursor.execute(sql)
#或附加数据
cursor.execut(sql, data)
db.commit()
except:
db.rollback()
db.close()
会用sql
查询的,这个可以直接上手用
3.3非关系型数据库MonogoDB保存
MongoDB是由C++语言编写的非关系型数据库,是一个基于分布式文件存储订单的开源数据库系统,其内存储存形式类似于JSON对象,他的字段值可以包含其他文档,数组以及文档数组,非常灵活。
官方文档
内容不多,能很快掌握
三.爬取猫眼电影前100
采用Requests
+ PyQuery
+JSON
1.源码
import requests
import json
import re
from pyquery import PyQuery as pq
def get_one_page(m_url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)\
Chrome/80.0.3987.106 Safari/537.36'
}
r = requests.get(m_url, headers=headers)
if r.status_code == 200:
return r.text
return None
def parser_one_page(m_html):
#正则表达式模板
"""patter = re.compile('<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>'
'.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</i>.*?'
'fraction.*?>(.*?)</i>.*?</dd>', re.S)
items = re.findall(patter, m_html)"""
#PyQuery
doc = pq(m_html)
for item in doc.find('dd').items():
yield {
'index': item('i.board-index').text(),
'image': item('img.board-img').attr('data-src'),
'title': item('p.name').children('a').text(),
'actor': item('p.star').text().strip()[3:] if len(item('p.star').text().strip()) > 3 else '',
'time': item('p.releasetime').text().strip()[5:] if len(item('p.releasetime').text().strip()) > 5 else '',
'score': item('p.score').children('i.integer').text().strip() +
item('p.score').children('i.fraction').text().strip()
}
def write_to_file(content):
with open('maoyan_result.txt', 'a', encoding='utf-8') as f:
f.write(json.dumps(content, indent=2, ensure_ascii=False) + '\n')
def run(offset):
url = 'http://maoyan.com/board/4?offset=' + str(offset)
html = get_one_page(url)
for item in parser_one_page(html):
write_to_file(item)
if __name__ == '__main__':
for i in range(10):
run(offset=i*10)
2.结果
参考资料:《Python3网络爬虫开发实践》,Google
如果对您有帮助,点赞、收藏、关注! 😃