前言

学习视频:尚硅谷

学习前最好是有一定的python基础,学习的效率会更加的好。

CTRL + / 快速注释

1.前提知识

1.序列化与反序列化

1.概念

通过文件操作,可以将字符串写入到一个本地文件。但是,如果是一个对象(例如列表、字典、元组等),就无法直接写入到一个文件里,需要对这个对象进行序列化,然后才能写入到文件里。

设计一套协议,按照某种规则,把内存中的数据转换为字节序列,保存到文件,这就是序列化,反之,从文件的字节序列恢复到内存中,就是反序列化。

  • 对象—>字节序列 === 序列化
  • 字节序列—>对象 ===反序列化

Python中提供了JSON这个模块用来实现数据的序列化和反序列化。

2.序列化的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
'''
对象 ---> 字节序列 == 序列化
'''
import json

#序列化有2种:dumps和dump

#第一种dumps
fp = open('test.txt','w')
name_list = ['zs','ls']
names = json.dumps(name_list)#序列化
fp.write(names)
fp.close()
print(names,type(names)) # 字符串类型

#第二种dump
#在将对象转换成字符串的同时,指定一个文件的对象,然后把转换后的字符串写入到这个文件里
fp = open('text.txt','w')
name_list = ['zs','ls']
json.dump(name_list,fp)#序列化
'''
相当于将
names = json.dumps(name_list)和
fp.write(names)
'''
fp.close()

3.反序列化的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 字节序列 变为 对象 == 反序列化
import json

#反序列化:loads,load
#将json的字符串变成一个python对象

#第一种loads
fp = open('test.txt','r')
content = fp.read()
result = json.loads(content)
print(result)
print(type(result))
fp.close()

#第二种load
fp = open('text.txt','r')
result = json.load(fp)
print(result)
print(type(result))
fp.close()

2.异常

1.概念

程序在运行过程中,由于编码不规范,或者其他原因一些客观原因,导致程序无法继续运行,此时,程序就会出现异常。如果我们不对异常进行处理,程序可能会由于异常直接中断掉。为了保证程序的健壮性,我们在程序设计里提出了异常处理这个概念。

2.try…except语句

1
2
3
4
5
6
7
8
9
10
11
12
# 语法:
try:
可能会出现异常的代码块
except 异常的类型:
出现异常以后的处理语句(友好的提示)

# 实例:
try:
f = open('test.txt', 'r')
print(f.read())
except FileNotFoundError:
print('文件没有找到,请检查文件名称是否正确')

3.网页页面结构的介绍

1.html文件

新建一个.html文件,初始的主体为:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

</body>
</html>

2.html的标签介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>

<body>
<!--
table 表格
tr 行
td 列
-->
<table width="200px" height="200px" border="1px">
<tr>
<td>
姓名
</td>
<td>
年龄
</td>
<td>
性别
</td>
</tr>

<tr>
<td>

</td>
<td>

</td>
<td>

</td>
</tr>
</table>

<!-- ul li 无序列表(爬虫使用的场景非常的多)-->
<ul>
<li>我最帅</li>
</ul>

<!-- ol li 有序列表-->
<ol>
<li>洗衣</li>
<li>吃饭</li>
</ol>

<!-- 超链接-->
<a href="https://silent-wuhen.github.io/">MyBlog</a>
</body>
</html>

4.URL(统一资源定位符)组成

1
2
3
4
#url的组成:协议(http/https),主机(www.baidu.com),端口号(80/443),路径,参数,锚点

#https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6
#协议:https 主机:www.baidu.com 端口号:443 路径:s 参数:?以后 锚点:#

5.什么是互联网爬虫

6.爬虫核心

  1. 爬取网页:爬取整个网页,包含了网页中所有的内容
  2. 解析数据:将网页中得到的数据进行解析
  3. 难点:爬虫与反爬虫之间的博弈

7.爬虫的用途

  1. 数据分析/人工数据集
  2. 社交软件冷启动
  3. 竞争对手的监控
  4. 舆情监控

8.爬虫的分类

1.通用爬虫(不是我们学习的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
实例:
百度、360、google、sougou等搜索引擎‐‐‐伯乐在线

功能:
访问网页‐>抓取数据‐>数据存储‐>数据处理‐>提供检索服务

robots协议:
一个约定俗成的协议,添加robots.txt文件,来说明本网站哪些内容不可以被抓取,起不到限制作用
自己写的爬虫无需遵守

网站排名(SEO):
1. 根据pagerank算法值进行排名(参考个网站流量、点击率等指标)
2. 百度竞价排名

缺点:
1. 抓取的数据大多是无用的
2.不能根据用户的需求来精准获取数据

2.聚焦爬虫

1
2
3
4
5
6
7
8
9
功能:
根据需求,实现爬虫程序,抓取需要的数据
设计思路:
1.确定要爬取的url
​如何获取url
2.模拟浏览器通过http协议访问url,获取服务器返回的html代码
​如何访问
3.解析html字符串(根据一定的规则提取需要的数据)
​如何解析

9.反爬虫手段?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1.User‐Agent:
​User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。

2.代理IP
​西次代理
​快代理
​什么是高匿名、匿名和透明代理?它们有什么区别?
1.使用透明代理,对方服务器可以知道你使用了代理,并且也知道你的真实IP。
2.使用匿名代理,对方服务器可以知道你使用了代理,但不知道你的真实IP。
3.使用高匿名代理,对方服务器不知道你使用了代理,更不知道你的真实IP。

3.验证码访问
​打码平台
​云打码平台
​超级🦅

4.动态加载网页
​网站返回的是js数据 并不是网页的真实数据
​selenium驱动真实的浏览器发送请求

5.数据加密
​分析js代码

2.Urllib

1.urllib库使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
urllib.request.urlopen() 模拟浏览器向服务器发送请求

response 服务器返回的数据
response的数据类型是HttpResponse
字节‐‐>字符串
解码decode
字符串‐‐>字节
编码encode
read() 字节形式读取二进制 扩展:rede(5)返回前几个字节
readline() 读取一行
readlines() 一行一行读取 直至结束
getcode() 获取状态码
geturl() 获取url
getheaders() 获取headers

urllib.request.urlretrieve()
请求网页
请求图片
请求视频

1.urllib的基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 使用urllib来获取百度首页的源码
import urllib.request

# (1)定义一个url:就是要访问的地址
url = 'http://www.baidu.com'

# (2)模拟浏览器向服务器发送请求
response = urllib.request.urlopen(url) # response响应:返回的数据

# (3)获取响应中的页面源码 content 内容
# read 返回的是字节形式的二进制数据
# 二进制-->字符串称为解码 使用的方法是decode('解码的格式')
content = response.read().decode('utf-8')

# (4)打印数据
print(content)

2.Urllib的1个类型和6个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import urllib.request

url = 'http://www.baidu.com'

# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(url)

# 一个类型和六个方法

#一个类型:HTTPResponse
# response是HTTPResponse数据类型的
print('response的数据类型:',type(response))

#六个方法:read() readline() readlines() getcode() geturl() getheaders()
# read()按照一个字节一个字节的读
content = response.read()
#print(content)

# 1.返回多少个字节
content = response.read(5)
#print(content)

# 2.读取一行(只能读取一行)
content = response.readline()
#print(content)

# 3.一行一行的读,读取所有行,要编码使用decode('utf-8')
content = response.readlines()
#print(content)

# 4.返回状态码 如果是200:证明逻辑正确(判断代码是否有问题)
print(response.getcode())

# 5.返回的是url的地址
print(response.geturl())

# 6.获取的是状态信息
print(response.getheaders())

3.Urllib的下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# urlretrieve(url,filename):url 下载路径,filename 文件的名字
import urllib.request

# 下载网页
url_page = 'http://www.baidu.com'
urllib.request.urlretrieve(url_page,'baidu.html')
# urllib.request.urlretrieve(url=url_page,filename='baidu.html')

# 下载图片
url_img = 'https://img2.baidu.com/it/u=2064031713,2731059264&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500'

urllib.request.urlretrieve(url_img,'平泽唯.jpg')

# 下载视频
url_video = 'https://vd7.bdstatic.com/mda-pdjhxmd8mxyvgexz/cae_h264/1682010451294745439/mda-pdjhxmd8mxyvgexz.mp4?v_from_s=hkapp-haokan-hbf&auth_key=1682077284-0-0-fbb39f9dcd76b70a58e232aa536a6a7b&bcevod_channel=searchbox_feed&pd=1&cd=0&pt=3&logid=0684217152&vid=9752895408415982948&abtest=109432_2-109133_1&klogid=0684217152&sdk_xcdn=1'

urllib.request.urlretrieve(url_video,'测试视频.mp4')

2.请求对象的定制

1.UA介绍:

User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本。浏览器内核、浏览器渲染引擎、浏览器语言、浏览器插件等

1
2
语法:
request = urllib.request.Request()

2.UA反爬

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#第一个反爬
import urllib.request

url = 'https://www.baidu.com'

#url的组成:协议(http/https),主机(www.baidu.com),端口号(80/443),路径,参数,锚点

#https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6
#协议:https 主机:www.baidu.com 端口号:443 路径:s 参数:?后面 锚点:#

'''
端口号
http 80
https 443
mysql 3306
oracle 1521
redis 6379
mongodb 27017
'''

# 反爬
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}
#请求对象的定制
#注:因为参数顺序为url,data,headers,不能直接写url和headers
request = urllib.request.Request(url = url,headers = headers)

response = urllib.request.urlopen(request)

content = response.read().decode('utf-8')

print(content)

3.扩展:编码

  1. ASCII编码:127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号。
  2. GB2312编码:用来把中文编进去。
  3. Unicode:最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。

3.编/解码

1.get请求方式:urllib.parse.quote()

将汉字变成Unicode编码

1
2
3
# 语法:
import urllib.parse
name = urllib.parse.quote('周杰伦')

实际例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
'''
需求
获取 https://www.baidu.com/s?wd=周杰伦 的网页源码
https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6
'''

import urllib.request
import urllib.parse

#将周杰伦转换为Unicode编码格式
name = urllib.parse.quote('周杰伦')

url = 'https://www.baidu.com/s?wd='
url = url + name

#解决反爬的手段
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}
# 请求对象的定制
request = urllib.request.Request(url = url,headers = headers)

# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)

# 获取响应的内容
content = response.read().decode('utf-8')

# 打印数据
print(content)

2.get请求方式:urllib.parse.urlencode()

  • 作用:将字典中多个中文转换成Unicode编码,并且键值之间使用“=”连接,键值对之外使用&连接。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
语法格式:

'''
import urllib.parse

data = {
'wd' : '周杰伦',
'sex' : '男'
}
a = urllib.parse.urlencode(data) # 将各个键值对用&连接起来
print(a)
输出结果为:
wd=%E5%91%A8%E6%9D%B0%E4%BC%A6&sex=%E7%94%B7
'''
  • 实际例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# urlencode应用场景:多个中文参数
# https://www.baidu.com/s?wd=周杰伦&sex=男

import urllib.request
import urllib.parse

data = {
'wd' : '周杰伦',
'sex' : '男'
}
data = urllib.parse.urlencode(data)

base_url = 'https://www.baidu.com/s?'
url = base_url + data
# print(url)

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}
request = urllib.request.Request(url = url,headers = headers)

response = urllib.request.urlopen(request)

content = response.read().decode('utf-8')

print(content)

3.post请求方式

步骤:

  1. 找post 请求的接口
  2. 怎么执行post请求(请求参数进行编码。编码之后 必须调用encode方法。)
  3. 传参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# post请求
import urllib.request
import urllib.parse

url = 'https://fanyi.baidu.com/sug'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}

data = {
'kw':'spider'
}

# post请求的参数 必须要进行编码encode('utf-8')
data = urllib.parse.urlencode(data).encode('utf-8')

# post请求的参数是不会拼接在url的后面,而是需放在请求对象定制的参数中
request = urllib.request.Request(url = url,data = data,headers = headers)

# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)

# 获取响应的数据
content = response.read().decode('utf-8')#str数据类型

print(content)

'''
post请求的参数 必须要进行编码 data = urllib.parse.urlencode(data).encode('utf-8')
参数是放在请求对象的定制方法中 request = urllib.request.Request(url = url,data = data,headers = headers)
'''

#字符串-->json对象
import json

print(type(content))
obj = json.loads(content)
print(obj)
print(type(obj))

4.总结:post和get区别?

  1. get请求方式的参数必须编码,参数是拼接到url后面,编码之后不需要调用encode方法
  2. post请求方式的参数必须编码,参数是放在请求对象定制的方法中,编码之后需要调用encode方法

5.百度翻译之详细翻译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import urllib.request
import urllib.parse

url = 'https://fanyi.baidu.com/v2transapi?from=en&to=zh'

headers = {
'Accept': '*/*',
# 'Accept-Encoding': 'gzip, deflate, br', # 这是编码格式,没有UTF-8,必须注释掉
'Accept-Language': 'zh-CN,zh;q=0.9',
'Acs-Token': '1705576134035_1705654546778_pgSxk6qRvhC4+gm1SagDeIwwKcAGC365pA/wc0YZZyri/YI6h/8LSa5pIQ1G2rdtWlVoV9ibHEqExlMbbtd8V/jAVJH2e8ZpisX3ddWOOmP/WnrBLhXD38MHyAwl5/XWsJffX33TRC4K9Vsz8zQOW4NPyG7kLTJZGPDTCv1iaYQWgr4WJbih1fOWAXb+MgTa15EDPWLWTw8+lVEQTvK8Oans77TkOwbjvcAE1l3a6YawdzjJI0NbYG+Xk9PnDmy3JAg+5r4cxuBhfc6K0mY+2mDbFQ3iQyEnSszmLxWvAo08dvBVc7m8I18SyiGbHzNdOPAu+Qep37iPKOklgqrShhz9+jQfQaeJ54E8N/HrV/9chA0aJqkqPcQyz1z8nXXn57TEFVZV8dhti5xv7lw0SJetoL8BGfInUYMtxOovg7VDvW4BI192MW2ocJaIu1NoDhrAtKSJb4I58Q3k0dxn/Pn40xyb35uXK1e5MUykZ3ThxdahuJLHaVch95PuMyG0GuWV1hcQc9Lq3jRLc/jrQw==',
'Connection': 'keep-alive',
'Content-Length': '149',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',

# 其中去决定性作用的是Cookie,其他的都是可以注释掉的
'Cookie': 'BIDUPSID=51D9D30414A922DDC3F952B560F37FC2; PSTM=1652673230; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BAIDUID=2552FC12B56D5C63A22F4860676B0A88:FG=1; BDUSS=25aNHBtd2VxOUgyNnpkUkd-TFJSejZJMWlFYU10ZjlMMEt6LTBldnlPcEJqb3BsSVFBQUFBJCQAAAAAAAAAAAEAAACDPaTeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEBY2VBAWNlb; BDUSS_BFESS=25aNHBtd2VxOUgyNnpkUkd-TFJSejZJMWlFYU10ZjlMMEt6LTBldnlPcEJqb3BsSVFBQUFBJCQAAAAAAAAAAAEAAACDPaTeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEBY2VBAWNlb; H_WISE_SIDS=39999_40016_40041; H_PS_PSSID=39999_40016_40041; H_WISE_SIDS_BFESS=39999_40016_40041; BAIDUID_BFESS=2552FC12B56D5C63A22F4860676B0A88:FG=1; BDRCVFR[A7hGrXFW48R]=K7PavkeTFPTUAN8ULuEQhPEUi4WU6; PSINO=2; BA_HECTOR=24a40la4a50l052h202h8k2gdtqjju1iqkdv61s; ZFY=JxHMjLMptFSB0Fx6rLKcRUU:AIGXbEGxWGnIfnIlrcrY:C; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1705150908,1705654260; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1705654540; ab_sr=1.0.1_MjBlNjBiNGE0YjVmNGI4NTRjYzBjYzUyYzU2Mzg4ZTZiMzY4Zjc3ODU1MzgwMjEyZGUwYjhhNDliYzZlYzM5M2U2YzZiNzQyOGZhNjc3OTNhY2JmM2ExNjg5YTdlOWY5Y2ZmODUwODViMTJmNjc3NGYwNzA0MmUwZTVjMzZhNmNiOTI4ZTBmNTQzZTgyYjgxYWRjNmQxN2Q0NmFiYTk4ZmZjOTdlZTYyMmJkMzY4ZTAwYTJiZjBhOGFkNWMxMTJi',
'Host': 'fanyi.baidu.com',
'Origin': 'https://fanyi.baidu.com',
'Referer': 'https://fanyi.baidu.com/translate?query=&keyfrom=baidu&smartresult=dict&lang=auto2zh',
'sec-ch-ua': '"Chromium";v="9", "Not?A_Brand";v="8"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 SLBrowser/9.0.0.10191 SLBChan/105',
'X-Requested-With': 'XMLHttpRequest'
}

data = {
'from': 'en',
'to': 'zh',
'query': 'love',
'transtype': 'enter',
'simple_means_flag': '3',
'sign': '198772.518981',
'token': '7483d683cdef5a92727320d35cbcdbf3',
'domain': 'common',
'ts': '1705654546761'
}

data = urllib.parse.urlencode(data).encode('utf-8')

# post请求的参数是不会拼接在url的后面,而是需放在请求对象定制的参数中
request = urllib.request.Request(url = url,data = data,headers = headers)

response = urllib.request.urlopen(request)

content = response.read().decode('utf-8')#str数据类型

print(content)

#字符串-->json对象

import json

obj = json.loads(content)

print(obj)

4.ajax的get请求

  • 案例1:豆瓣电影第一页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# get请求
# 获取第一页数据并且保存
import urllib.request

url = 'https://movie.douban.com/j/chart/top_list?type=6&interval_id=100%3A90&action=&start=0&limit=20'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}
request = urllib.request.Request(url = url,headers = headers)

response = urllib.request.urlopen(request)

content = response.read().decode('utf-8')

#print(content)

# open默认使用的是gbk的编码
# fp = open("douban.json",'w',encoding='utf-8')
# fp.write(content) # ctrl+alt+l 调整格式
# fp.close
with open('豆瓣.json','w',encoding='utf-8') as fp:
fp.write(content)

  • 案例2:豆瓣电影前10页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
'''
https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&
start=0&limit=20

https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&
start=20&limit=20

https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&
start=40&limit=20

规律:
start : (page - 1) * 20

步骤:
1.请求对象的定制
2.获取相应的数据
3.数据下载
'''

import urllib.request
import urllib.parse

def create_request(page):
base_url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&'

data = {
'start' : (page - 1) * 20,
'limit' : 20
}

data = urllib.parse.urlencode(data)
url = base_url + data
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}
request = urllib.request.Request(url = url, headers = headers)
return request

def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content

def down_load(page,content):
with open("豆瓣" + str(page) + ".json",'w',encoding='utf-8') as fp:
fp.write(content)

# 程序的入口
if __name__ == '__main__':
start = int(input("请输入起始的页码:"))
end = int(input("请输入结束的页码:"))
for page in range(start,end +1):
# 每页都需要进行请求对象的定制
request = create_request(page)
# 获取的响应的数据
content = get_content(request)
# 下载
down_load(page,content)


5.ajax的post请求

  • 案例:爬取肯德基官网
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
'''
page 1
http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname
post请求
cname: 北京
pid:
pageIndex: 1
pageSize: 10

page 2
http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname
post请求
cname: 北京
pid:
pageIndex: 2
pageSize: 10

规律:pageIndex(第几页就是几)
'''


import urllib.request
import urllib.parse

def create_request():
base_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'
data = {
'post':'请求',
'cname':'北京',
'pid':'',
'pageIndex': 2,
'pageSize': 10
}
data = urllib.parse.urlencode(data).encode('utf-8')

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}

request = urllib.request.Request(url=base_url,data=data,headers=headers)
return request

def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content


def down_load(page,content):
with open('肯德基_'+str(page)+'.json','w',encoding='utf-8') as fp:
fp.write(content)

if __name__ == '__main__':
start_page = int(input("请输入起始页码:"))
end_page = int(input("请输入终止页码:"))

for page in range(start_page,end_page + 1):
request = create_request()
content = get_content(request)
down_load(page,content)

6.URLError\HTTPError

1
2
3
4
5
6
7
8
简介:
1.HTTPError类是URLError类的子类

2.导入的包urllib.error.HTTPError urllib.error.URLError

3.http错误:http错误是针对浏览器无法连接到服务器而增加出来的错误提示。引导并告诉浏览者该页是哪里出了问题。

4.通过urllib发送请求的时候,有可能会发送失败,这个时候如果想让你的代码更加的健壮,可以通过tryexcept进行捕获异常,异常有两类,URLError\HTTPError
  • 案例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import urllib.request
import urllib.error

# import

# url = 'https://blog.csdn.net/Purpleendurer/article/details/135156750' # 正确的url

# url = 'https://blog.csdn.net/Purpleendurer/article/details/13515675011' # httperror

url = 'http://www.hqhwwww.com' # urlerror

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}

try:
request = urllib.request.Request(url=url,headers=headers)

response = urllib.request.urlopen(request)

content = response.read().decode('utf-8')

print(content)
except urllib.error.HTTPError:
print('系统正在升级')
except urllib.error.URLError:
print("嗯,还在升级")

7.cookie登录

  • 案例:微博登录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
'''
适用的场景:数据采集的时候,需要绕过登录,然后进入到某个页面
个人信息页面是utf-8,但是还是保编码错误,因为没有登录信息页面,而是跳转到了登录页面,登录页面不是UTF-8,所以报错


'''
import urllib.request

url = 'https://m.weibo.cn/users/2906598961?set=1'

headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-language': 'zh-CN,zh;q=0.9',
'cache-control': 'max-age=0',

# cookie中携带着登录信息,如果有登录之后的cookie 那么我们可以携带着cookie进入任何页面
'cookie': '_T_WM=f2795e7918b16c688965f9651943adf8; XSRF-TOKEN=f01dfc; MLOGIN=1; SUB=_2A25Ir4huDeRhGeRH61QU-SbFzT2IHXVrxIWmrDV6PUJbktAGLU_EkW1NTfzTjDYP_oJIck5f95UkomM2UsPW2zlt; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9W5FThBRqddjayf_HAMY69ZD5JpX5KzhUgL.Foz4ehqf1Kn4So22dJLoIX5LxK-L12qLB--LxK-LB.BL1KeLxKqLBoeL1K-LxKqL1-eLB-qLxK-L12qL1KnLxK-L12qL1KnLxK-L12qL1KnE; SSOLoginState=1705769022; ALF=1708361022',
# referer(做防盗链) 判断当前路径是不是由上一个路径进来的,一般情况下是做图片的防盗链
'referer': 'https://m.weibo.cn/profile/2906598961',

'sec-ch-ua': '"Chromium";v="9", "Not?A_Brand";v="8"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'same-origin',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 SLBrowser/9.0.0.10191 SLBChan/105'
}

request = urllib.request.Request(url=url,headers=headers)

response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')

with open('weibo.html','w',encoding='utf-8') as fp:
fp.write(content)

8.Handler处理器

1
2
3
4
5
6
7
8
为什么要学习handler?
urllib.request.urlopen(url)
不能定制请求头
urllib.request.Request(url,headers,data)
可以定制请求头

Handler
定制更高级的请求头(随着业务逻辑的复杂 请求对象的定制已经满足不了我们的需求(动态cookie和代理不能使用请求对象的定制)
  • 案例:handler的基本使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import urllib.request

url = 'http://www.baidu.com'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}

request = urllib.request.Request(url=url,headers=headers)

# handler build_opener open

#(1)获取handler对象
handler = urllib.request.HTTPHandler()
#(2)获取opener对象
opener = urllib.request.build_opener(handler)
#(3)调用open方法
response = opener.open(request)

content = response.read().decode('utf-8')
print(content)

9.代理服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.代理的常用功能?
1.突破自身IP访问限制,访问国外站点。
2.访问一些单位或团体内部资源
扩展:某大学FTP(前提是该代理地址在该资源的允许访问范围之内),使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。
3.提高访问速度
扩展:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。
4.隐藏真实IP
扩展:上网者也可以通过这种方法隐藏自己的IP,免受攻击。

2.代码配置代理
创建Reuqest对象
创建ProxyHandler对象
用handler对象创建opener对象
使用opener.open函数发送请求
  • 案例1:快代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import urllib.request

url = 'http://www.ip138.com/'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}

request = urllib.request.Request(url=url,headers=headers)

# response = urllib.request.urlopen(request)

# https://www.kuaidaili.com/free/ 快代理的网址
proxies = {
'http:':'175.167.21.80:23443'
}
handler = urllib.request.ProxyHandler()
opener = urllib.request.build_opener(handler)
response = opener.open(request)

content = response.read().decode('utf-8')

with open('daili.html','w',encoding='utf-8') as fp:
fp.write(content)
  • 案例2:代理池
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import random
import urllib.request

proxies_pool = [
{'http:':'175.167.21.80:23443'},
{'http:':'175.167.21.80:23443'},
{'http:':'175.167.21.80:23443'}
]

proxies = random.choice(proxies_pool)

url = 'http://www.ip138.com/'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}

request = urllib.request.Request(url=url,headers=headers)

handler = urllib.request.ProxyHandler()
opener = urllib.request.build_opener(handler)
response = opener.open(request)

content = response.read().decode('utf-8')

with open('daili.html','w',encoding='utf-8') as fp:
fp.write(content)

3.解析

1.xpath

  • 安装xpath
1
2
3
4
5
6
7
8
9
10
11
12
13
14
xpath使用:
注意:提前安装xpath插件
1)ctrl + shift + x 启动扩展

1.安装lxml库
pip install lxml -i https://pypi.douban.com/simple
2.导入lxml.etree
from lxml import etree
3.etree.parse() 解析本地文件
html_tree = etree.parse('XX.html')
4.etree.HTML() 服务器响应文件
html_tree = etree.HTML(response.read().decode('utf‐8')
4.语法的格式:
html_tree.xpath(xpath路径)
  • xpath的基本语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1.路径查询
//:查找所有子孙节点,不考虑层级关系
/ :找直接子节点
2.谓词查询
//div[@id]
//div[@id="maincontent"]
3.属性查询
//@class
4.模糊查询
//div[contains(@id, "he")]
//div[starts‐with(@id, "he")]
5.内容查询
//div/h1/text()
6.逻辑运算
//div[@id="head" and @class="s_down"]
//title | //price
  • 例子演示:

    1. 数据的准备

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8"/>
      <title>Title</title>
      </head>
      <body>
      <ul>
      <li id="l1" class="c1">北京</li>
      <li id="l2">上海</li>
      <li id="c3">深圳</li>
      <li id="c4">武汉</li>
      </ul>

      <ul>
      <li>大连</li>
      <li>锦州</li>
      <li>沈阳</li>
      </ul>
      </body>
      </html>
    2. 演示的代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      from lxml import etree

      '''
      xpath解析
      (1)本地文件
      html_tree = etree.parse('XX.html')
      (2)服务器相应的数据
      html_tree = etree.HTML(response.read().decode('utf‐8')
      '''

      # xpath解析本地文件
      tree = etree.parse('1.解析_xpath的基本使用.html')
      # tree.xpath('xpath的路径')
      # (1)查找ul下的li
      li_list = tree.xpath('//body/ul/li')
      print(len(li_list))
      # (2)谓词查询 需求:查找所有id属性的li标签
      li_list = tree.xpath('//ul/li[@id]')
      print(len(li_list))
      # (3)查找id为l1的li标签
      li_list = tree.xpath('//ul/li[@id="l1"]/text()')
      print(li_list)
      # (4)查找到id为l1的li标签的class的属性值
      li = tree.xpath('//ul/li[@id="l1"]/@class')
      print(li,len(li))
      # (5)查询id中包含l的li标签
      li = tree.xpath('//ul/li[contains(@id, "l")]/text()')
      print(li,len(li))
      # (6)查询id的值以l开头的li标签
      li = tree.xpath('//ul/li[starts-with(@id,"c")]/text()')
      print(li,len(li))
      # (7)逻辑运算 查询id为l1和class为c1的
      li = tree.xpath('//ul/li[@id="l1" and @class="c1"]/text()')
      print(li,len(li))

      li = tree.xpath('//ul/li[@id="l1"]/text() | //ul/li[@id="l2"]/text()')
      print(li,len(li))


  • 案例1:获取百度网站的:”百度一下”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
'''
需求:
获取百度一下这4个字
1.获取网页的源码
2.解析
'''
import urllib.request
from lxml import etree

url = 'https://www.baidu.com'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}

request = urllib.request.Request(url=url,headers=headers)

response = urllib.request.urlopen(request)

content = response.read().decode('utf-8')

# 解析网页的源码 获取我们想要的数据

# 解析服务器响应的文件
tree = etree.HTML(content)

# 获取想要的数据,xpath返回的数据为列表数据类型
result = tree.xpath('//input[@id="su"]/@value')[0]

print(result)

  • 案例:站长素材
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
'''
需求:https://sc.chinaz.com/下载前5页的地址
第1页:https://sc.chinaz.com/tupian/qinglvtupian.html
第2页:https://sc.chinaz.com/tupian/qinglvtupian_2.html
第3页:https://sc.chinaz.com/tupian/qinglvtupian_3.html

(1)请求对象的定制
(2)获取网页的源码
(3)下载
'''

import urllib.request
from lxml import etree

def create_request(page):
if page == 1:
url = 'https://sc.chinaz.com/tupian/qinglvtupian.html'
else:
url = 'https://sc.chinaz.com/tupian/qinglvtupian_' + str(page) +'.html'

headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.48'
}
request = urllib.request.Request(url=url, headers=headers)
return request

def get_content(request):
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
return content

def down_load(content):
# 下载图片 urllib.request.urlretrieve('图片的地址','图片的名字')
tree = etree.HTML(content)

name_list = tree.xpath('//div//img/@alt')
# 一般涉及到图片的时候都会进行懒加载(可能路径会发生变化)
Img_list = tree.xpath('//div[@class="container"]//img/@data-original')

for i in range(len(name_list)):
url = 'https:' + Img_list[i]
name = './123/' + name_list[i] + '.jpg'
urllib.request.urlretrieve(url,name)


if __name__ == '__main__':
start = int(input("请输入起始的页码:"))
end = int(input("请输入结束的页码:"))

for page in range(start,end+1):
request = create_request(page)
content = get_content(request)
down_load(content)
print("第%d页下载完成"%(page))

2.JsonPath

  • 只能识别本地文件
  1. 安装与使用

    教程链接

    1
    2
    3
    4
    5
    pip安装:
    pip install jsonpath
    jsonpath的使用:
    obj = json.load(open('json文件路径', 'r', encoding='utf‐8'))
    ret = jsonpath.jsonpath(obj, 'jsonpath语法')

    001.png

  2. 案例(淘票票)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    import urllib.request

    url = 'https://dianying.taobao.com/cityAction.json?activityId&_ksTS=1629789477003_137&jsoncallback=jsonp138&action=cityAction&n_s=new&event_submit_doGetAllRegion=true'

    headers = {
    # ':authority': 'dianying.taobao.com',
    # ':method': 'GET',
    # ':path': '/cityAction.json?activityId&_ksTS=1629789477003_137&jsoncallback=jsonp138&action=cityAction&n_s=new&event_submit_doGetAllRegion=true',
    # ':scheme': 'https',
    'accept': 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01',
    # 'accept-encoding': 'gzip, deflate, br',
    'accept-language': 'zh-CN,zh;q=0.9',
    'cookie': 'cna=UkO6F8VULRwCAXTqq7dbS5A8; miid=949542021157939863; sgcookie=E100F01JK9XMmyoZRigjfmZKExNdRHQqPf4v9NIWIC1nnpnxyNgROLshAf0gz7lGnkKvwCnu1umyfirMSAWtubqc4g%3D%3D; tracknick=action_li; _cc_=UIHiLt3xSw%3D%3D; enc=dA18hg7jG1xapfVGPHoQCAkPQ4as1%2FEUqsG4M6AcAjHFFUM54HWpBv4AAm0MbQgqO%2BiZ5qkUeLIxljrHkOW%2BtQ%3D%3D; hng=CN%7Czh-CN%7CCNY%7C156; thw=cn; _m_h5_tk=3ca69de1b9ad7dce614840fcd015dcdb_1629776735568; _m_h5_tk_enc=ab56df54999d1d2cac2f82753ae29f82; t=874e6ce33295bf6b95cfcfaff0af0db6; xlly_s=1; cookie2=13acd8f4dafac4f7bd2177d6710d60fe; v=0; _tb_token_=e65ebbe536158; tfstk=cGhRB7mNpnxkDmUx7YpDAMNM2gTGZbWLxUZN9U4ulewe025didli6j5AFPI8MEC..; l=eBrgmF1cOsMXqSxaBO5aFurza77tzIRb8sPzaNbMiInca6OdtFt_rNCK2Ns9SdtjgtfFBetPVKlOcRCEF3apbgiMW_N-1NKDSxJ6-; isg=BBoas2yXLzHdGp3pCh7XVmpja8A8S54lyLj1RySTHq14l7vRDNufNAjpZ2MLRxa9',
    'referer': 'https://dianying.taobao.com/',
    'sec-ch-ua': '"Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"',
    'sec-ch-ua-mobile': '?0',
    'sec-fetch-dest': 'empty',
    'sec-fetch-mode': 'cors',
    'sec-fetch-site': 'same-origin',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
    'x-requested-with': 'XMLHttpRequest',
    }

    request = urllib.request.Request(url=url,headers=headers)
    response = urllib.request.urlopen(request)
    content = response.read().decode('utf-8')
    # print(content)

    content = content.split('(')[1].split(')')[0]

    with open('5._解析_jsonpath解析淘票票.json','w',encoding='utf-8') as fp:
    fp.write(content)

    import json
    import jsonpath
    obj = json.load(open('5._解析_jsonpath解析淘票票.json','r',encoding='utf-8'))

    city_list = jsonpath.jsonpath(obj,'$..regionName')
    print(city_list)

3.BeautifulSoup

  1. 基本简介

    1
    2
    3
    4
    5
    6
    7
    1.BeautifulSoup简称:
    bs4
    2.什么是BeatifulSoup?
    BeautifulSoup,和lxml一样,是一个html的解析器,主要功能也是解析和提取数据
    3.优缺点?
    缺点:效率没有lxml的效率高
    优点:接口设计人性化,使用方便
  2. 安装以及创建

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    1.安装
    pip install bs4
    2.导入
    from bs4 import BeautifulSoup
    3.创建对象
    服务器响应的文件生成对象
    soup = BeautifulSoup(response.read().decode(), 'lxml')
    本地文件生成对象
    soup = BeautifulSoup(open('6.解析_bs4的基本使用.html',encoding='utf-8'),'lxml')
    注意:默认打开文件的编码格式gbk所以需要指定打开编码格式
  3. 节点定位

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    1.根据标签名查找节点
    soup.a 【注】只能找到第一个a
    soup.a.name
    soup.a.attrs # 获取标签的属性和属性值
    2.函数
    (1).find(返回一个对象)
    find('a'):只找到第一个a标签
    (2).find_all(返回一个列表)
    find_all('a') 查找到所有的a
    find_all(['a', 'span']) 返回所有的a和span
    find_all('a', limit=2) 只找前两个a
    (3).select(根据选择器得到节点对象)【推荐】
    1.element
    eg:p
    2..class
    eg:.firstname
    3.#id
    eg:#firstname
    4.属性选择器
    [attribute]
    eg:li = soup.select('li[class]')
    [attribute=value]
    eg:li = soup.select('li[class="hengheng1"]')
    5.层级选择器
    element element
    div p
    element>element
    div>p
    element,element
    div,p
    eg:soup = soup.select('a,span')
  4. 节点信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    (1).获取节点内容:适用于标签中嵌套标签的结构
    obj.string
    obj.get_text()【推荐】
    (2).节点的属性
    tag.name 获取标签名
    eg:tag = find('li)
    print(tag.name)
    tag.attrs将属性值作为一个字典返回
    (3).获取节点属性
    obj.attrs.get('title')【常用】
    obj.get('title')
    obj['title']
  5. 案例(星巴克数据)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # 时间问题,代码已经失效 
    import urllib.request

    url = 'https://www.starbucks.com.cn/menu/'

    response = urllib.request.urlopen(url)

    content = response.read().decode('utf-8')


    from bs4 import BeautifulSoup

    soup = BeautifulSoup(content,'lxml')

    # //ul[@class="grid padded-3 product"]//strong/text()
    name_list = soup.select('ul[class="grid padded-3 product"] strong')

    for name in name_list:
    print(name.get_text())

4.selenium

1.selenium概述

  1. selenium概念

    1
    2
    3
    4
    (1)Selenium是一个用于Web应用程序测试的工具。
    (2)Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样。
    (3)支持通过各种driver(FirfoxDriver,IternetExplorerDriver,OperaDriver,ChromeDriver)驱动真实浏览器完成测试。
    (4)selenium也是支持无界面浏览器操作的。
  2. 为什么使用selenium

    1
    模拟浏览器功能,自动执行网页中的js代码,实现动态加载
  3. 安装selenium

    1
    2
    3
    4
    5
    6
    7
    (1)操作谷歌浏览器驱动下载地址
    http://chromedriver.storage.googleapis.com/index.html
    (2)谷歌驱动和谷歌浏览器版本之间的映射表
    http://blog.csdn.net/huilan_same/article/details/51896672
    (3)查看谷歌浏览器版本
    谷歌浏览器右上角‐‐>帮助‐‐>关于
    (4)pip install selenium
  4. selenium的使用步骤

    1
    2
    3
    4
    5
    6
    7
    (1)导入:from selenium import webdriver
    (2)创建谷歌浏览器操作对象:
    path = 谷歌浏览器驱动文件路径
    browser = webdriver.Chrome(path)
    (3)访问网址
    url = 要访问的网址
    browser.get(url)
  5. selenium的元素定位

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    元素定位:自动化要做的就是模拟鼠标和键盘来操作来操作这些元素,点击、输入等等。操作这些元素前首先要找到它们,WebDriver提供很多定位元素的方法

    方法:
    1.find_element_by_id
    eg:button = browser.find_element_by_id('su')
    2.find_elements_by_name
    eg:name = browser.find_element_by_name('wd')
    3.find_elements_by_xpath
    eg:xpath1 = browser.find_elements_by_xpath('//input[@id="su"]')
    4.find_elements_by_tag_name
    eg:names = browser.find_elements_by_tag_name('input')
    5.find_elements_by_css_selector
    eg:my_input = browser.find_elements_by_css_selector('#kw')[0]
    6.find_elements_by_link_text
    eg:browser.find_element_by_link_text("新闻")
  6. 访问元素信息

    1
    2
    3
    4
    5
    6
    1.获取元素属性
    .get_attribute('class')
    2.获取元素文本
    .text
    3.获取标签名
    .tag_name
  7. 交互

    1
    2
    3
    4
    5
    6
    7
    8
    9
    点击:click()
    输入:send_keys()
    后退操作:browser.back()
    前进操作:browser.forword()
    模拟JS滚动:
    js='document.documentElement.scrollTop=100000'
    browser.execute_script(js) 执行js代码
    获取网页代码:page_source
    退出:browser.quit()

2.Chrome handless

Chrome-headless 模式, Google 针对 Chrome 浏览器 59版 新增加的一种模式,可以不打开UI界面的情况下使用 Chrome 浏览器,所以运行效果与 Chrome 保持完美一致

  1. 系统要求:

    1
    2
    3
    4
    5
    6
    Chrome
    Unix\Linux 系统需要 chrome >= 59
    Windows 系统需要 chrome >= 60
    Python3.6
    Selenium==3.4.*
    ChromeDriver==2.31
  2. 配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options

    chrome_options = Options()
    chrome_options.add_argument('‐‐headless')
    chrome_options.add_argument('‐‐disable‐gpu')

    path = r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
    chrome_options.binary_location = path
    browser = webdriver.Chrome(chrome_options=chrome_options)

    browser.get('http://www.baidu.com/')
  3. 配置封装:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from selenium import webdriver
    #这个是浏览器自带的 不需要再做额外的操作
    from selenium.webdriver.chrome.options import Options

    def share_browser():
    #初始化
    chrome_options = Options()
    chrome_options.add_argument('‐‐headless')
    chrome_options.add_argument('‐‐disable‐gpu')
    #浏览器的安装路径 打开文件位置
    #这个路径是你谷歌浏览器的路径
    path = r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
    chrome_options.binary_location = path
    browser = webdriver.Chrome(chrome_options=chrome_options)
    return browser
  4. 封装调用

    1
    2
    3
    4
    5
    6
    7
    from handless import share_browser

    browser = share_browser()

    browser.get('http://www.baidu.com/')

    browser.save_screenshot('handless1.png')

5.requests

1.基本使用

  1. 文档

    1
    2
    3
    4
    官方文档
    http://cn.python‐requests.org/zh_CN/latest/
    快速上手
    http://cn.python‐requests.org/zh_CN/latest/user/quickstart.html
  2. 安装

    1
    pip install requests
  3. response的属性以及类型

    1
    2
    3
    4
    5
    6
    7
    类型			   :models.Response
    r.text :获取网站源码
    r.encoding :访问或定制编码方式
    r.url :获取请求的url
    r.content :响应的字节类型
    r.status_code :响应的状态码
    r.headers :响应的头信息

2.get请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
requests.get()

eg:
import requests
url = 'http://www.baidu.com/s?'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'

}
data = {
'wd':'北京'
}
response = requests.get(url,params=data,headers=headers)

定制参数
参数使用params传递
参数无需urlencode编码
不需要请求对象的定制
请求资源路径中?可加可不加

3.post请求

1
2
3
4
5
6
7
8
9
10
11
12
13
requests.post()

百度翻译:
eg:
import requests
post_url = 'http://fanyi.baidu.com/sug'
headers={
'User‐Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
data = {
'kw': 'eye'
}
r = requests.post(url = post_url,headers=headers,data=data)
  • get和post区别?
    1. get请求的参数名字是params post请求的参数的名字是data
    2. 请求资源路径后面可以不加?
    3. 不需要手动编解码
    4. 不需要做请求对象的定制

4.代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'''
proxy定制
在请求中设置proxies参数
参数类型是一个字典类型
'''

eg:
import requests
url = 'http://www.baidu.com/s?'
headers = {
'user‐agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/65.0.3325.181 Safari/537.36'
}
data = {
'wd':'ip'
}
proxy = {
'http':'219.149.59.250:9797'
}
r = requests.get(url=url,params=data,headers=headers,proxies=proxy)
with open('proxy.html','w',encoding='utf‐8') as fp:
fp.write(r.text)

5.cookie定制

1
2
3
4
5
应用案例:
(1)古诗文网(需要验证)
(2)云打码平台
用户登陆 actionuser action
开发者登陆 actioncode action

6.scrapy

1.scrapy概述

1.认识scrapy

  1. scrapy是什么?

    1
    Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
  2. 安装scrapy:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    pip install scrapy

    (1)安装出错,且报错信息:
    pip install Scrapy
    building 'twisted.test.raiser' extension
    error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual‐cpp‐build‐tools

    解决方案:
    1.进入:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
    2.下载twisted对应版本的whl文件(如Twisted‐17.5.0‐cp36‐cp36m‐win_amd64.whl),cp后面是 python版本,amd64代表64位
    3.运行命令:
    pip install C:\Users\...\Twisted‐17.5.0‐cp36‐cp36m‐win_amd64.whl # 本地文件
    pip install Scrapy

    (2)若再报错
    python ‐m pip install ‐‐upgrade pip

    (3)若再报错:win32
    解决方法:
    pip install pypiwin32

    (4)若再报错:使用anaconda

2.scrapy项目的创建以及运行

  1. 创建scrapy项目,在终端输入:

    1
    scrapy startproject 项目名称
  2. 项目组成:

    1
    2
    3
    4
    5
    6
    7
    8
    spiders # 存储爬虫文件
    __init__.py
    自定义的爬虫文件.py # 由我们自己创建,是实现爬虫核心功能的文件
    __init__.py
    items.py # 定义数据结构的地方,是一个继承自scrapy.Item的类
    middlewares.py # 中间件,代理
    pipelines.py # 管道文件,里面只有一个类,用于处理下载数据的后续处理[默认是300优先级,值越小优先级越高(1‐1000)]
    settings.py # 配置文件 比如:是否遵守robots协议,User‐Agent定义等
  3. 创建爬虫文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    创建爬虫文件:
    (1)跳转到spiders文件夹:cd 目录名字/目录名字/spiders
    (2)scrapy genspider 爬虫名字 网页的域名(一般不写http://)
    eg:scrapy genspider baidu www.baidu.com

    爬虫文件的基本组成(继承scrapy.Spider类):
    name = 'baidu' # 运行爬虫文件时使用的名字
    allowed_domains # 爬虫允许的域名,在爬取的时候,如果不是此域名之下的url,会被过滤掉
    start_urls # 声明了爬虫的起始地址,可以写多个url,一般只有一个。注:html的url最后不能有/
    parse(self, response) # 解析数据的回调函数
    response.text # 响应的是字符串
    response.body # 响应的是二进制文件
    response.xpath() # xpath方法的返回值类型是selector列表
    extract() # 提取的是selector对象的是data
    extract_first() # 提取的是selector列表中的第一个数据
  4. 运行爬虫文件,cmd输入:

    1
    2
    scrapy crawl 爬虫名称
    # 注意:应在spiders文件夹内执行

3.scrapy架构组成

1
2
3
4
5
6
7
8
9
10
11
(1)引擎:自动运行,无需关注,会自动组织所有的请求对象,分发给下载器
(2)下载器:从引擎处获取到请求对象后,请求数据
(3)spiders:Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是您定义爬取的动作及分析某个网页(或者是有些网页)的地方。
(4)调度器:有自己的调度规则,无需关注
(5)管道(Item pipeline):最终处理数据的管道,会预留接口供处理数据
当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。
以下是item pipeline的一些典型应用:
1. 清理HTML数据
2. 验证爬取的数据(检查item包含某些字段)
3. 查重(并丢弃)
4. 将爬取结果保存到数据库中

4.scrapy工作原理

001.png

2.scrapy shell

  1. scrapy shell介绍

    1
    2
    Scrapy终端,是一个交互终端,在未启动spider的情况下尝试及调试爬取代码。 其本意是用来测试提取数据的代码,可将其作为正常的Python终端,在上面测试任何的Python代码。
    该终端是用来测试XPath或CSS表达式,查看他们的工作方式及从爬取的网页中提取的数据。在编写spider时,该终端提供了交互性测试表达式代码的功能,免去了每次修改后运行spider的麻烦。一旦熟悉了Scrapy终端后,其在开发和调试spider时发挥的巨大作用。
  2. 安装ipython

    1
    pip install ipython
  3. 应用

    1
    2
    3
    (1)scrapy shell www.baidu.com
    (2)scrapy shell http://www.baidu.com
    (3) scrapy shell "http://www.baidu.com"

3.yield

1.概念

  1. 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
  2. yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yield后面(右边)的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码(下一行)开始执行
  3. 简要理解:yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始

2.案例1(按页下载):爬取汇书网

  1. 创建项目:切换到项目存放目录,创建项目。

    1
    2
    3
    cd C:\Users\wuhen\Desktop

    scrapy startproject hsw
  2. 创建爬虫文件:进入爬虫存储文件,创建爬虫。

    1
    2
    3
    cd hsw/hsw/spiders

    scrapy genspider hsw_spider https://www.huibooks.com/wx
  3. 爬虫运行:

    1
    2
    # 运行代码
    scrapy crawl hsw_spider
  4. 编写爬虫:打开项目,检查hsw_spider.py的name、allowed_domains、start_urls,编写初步的爬虫.(若运行报错,关闭settings.py的ROBOTSTXT_OBEY)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class HswSpiderSpider(scrapy.Spider):
    name = "hsw_spider"
    allowed_domains = ["www.huibooks.com"]
    start_urls = ["https://www.huibooks.com/wx"]

    def parse(self, response):
    src_list = response.xpath('//li[@class="post-list-item item-post-style-1"]//img/@src')
    name_list = response.xpath('//li[@class="post-list-item item-post-style-1"]//img/@alt')
    number_list = response.xpath('//li[@class="post-list-meta-views"]/span/text()')

    for i in range(len(src_list)):
    src = src_list[i].extract()
    name = name_list[i].extract()
    number = number_list[i].extract()
    print(src,name,number)
  5. 定义数据结构:在items.py编写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # Define here the models for your scraped items
    #
    # See documentation in:
    # https://docs.scrapy.org/en/latest/topics/items.html

    import scrapy


    class HswItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    src = scrapy.Field()
    name = scrapy.Field()
    number = scrapy.Field()


  6. 管道文件:在pipelines.py下,处理下载的数据。

    在settings.py打开:

    1
    2
    3
    ITEM_PIPELINES = {
    "hsw.pipelines.HswPipeline": 300,
    }

    注:只能是open_spider和close_spider。写入时只能是字符串对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class HswPipeline:
    def open_spider(self, spider):
    self.fp = open('books.json', 'w', encoding='utf-8')

    def process_item(self, item, spider):
    self.fp.write(str(item))
    return item

    def close_spider(self, spidre):
    self.fp.close()
  7. 导入数据结构方面,创建数据结构,存储数据

    在hsw_spider.py中输入:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import scrapy
    from hsw.items import HswItem


    class HswSpiderSpider(scrapy.Spider):
    name = "hsw_spider"
    allowed_domains = ["www.huibooks.com"]
    start_urls = ["https://www.huibooks.com/wx"]

    def parse(self, response):
    src_list = response.xpath('//li[@class="post-list-item item-post-style-1"]//img/@src')
    name_list = response.xpath('//li[@class="post-list-item item-post-style-1"]//img/@alt')
    number_list = response.xpath('//li[@class="post-list-meta-views"]/span/text()')

    for i in range(len(src_list)):
    src = src_list[i].extract()
    name = name_list[i].extract()
    number = number_list[i].extract()

    book = HswItem(src=src, name=name, number=number)

    yield book
  8. 开启多条管道(注意shell运行的路径)

    • 定义管道类:在pipelines.py下添加类:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22

      class HswPipeline:
      def open_spider(self, spider):
      self.fp = open('books.json', 'w', encoding='utf-8')

      def process_item(self, item, spider):
      self.fp.write(str(item))
      return item

      def close_spider(self, spidre):
      self.fp.close()

      import urllib.request

      class HswDownloadPipeline:
      def process_item(self, item, spider):
      url = item.get("src")
      filename = './books/' + item.get("name") + '.jpg'

      urllib.request.urlretrieve(url=url,filename=filename)

      return item
    • 在settings.py中开启管道

      1
      2
      3
      4
      ITEM_PIPELINES = {
      "hsw.pipelines.HswPipeline": 300,
      "hsw.pipelines.HswDownloadPipeline":301,
      }
  9. 多页数据下载

    • 找到url的规律

      1
      2
      3
      # https://www.huibooks.com/wx
      # https://www.huibooks.com/wx/page/2
      # https://www.huibooks.com/wx/page/3
    • 调用hsw_spider.py中的parse函数

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      import scrapy
      from hsw.items import HswItem


      class HswSpiderSpider(scrapy.Spider):
      name = "hsw_spider"
      allowed_domains = ["www.huibooks.com"]
      start_urls = ["https://www.huibooks.com/wx"]

      base_url = 'https://www.huibooks.com/wx/page/'
      page = 1

      def parse(self, response):
      src_list = response.xpath('//li[@class="post-list-item item-post-style-1"]//img/@src')
      name_list = response.xpath('//li[@class="post-list-item item-post-style-1"]//img/@alt')
      number_list = response.xpath('//li[@class="post-list-meta-views"]/span/text()')

      for i in range(len(src_list)):
      src = src_list[i].extract()
      name = name_list[i].extract()
      number = number_list[i].extract()

      book = HswItem(src=src, name=name, number=number)

      yield book


      # https://www.huibooks.com/wx
      # https://www.huibooks.com/wx/page/2
      # https://www.huibooks.com/wx/page/3
      if self.page < 3:
      self.page += 1

      url = self.base_url + str(self.page)

      # 调用parse方法
      # scrapy.Request就是 scrapy 的get请求
      yield scrapy.Request(url=url,callback=self.parse) # callback调用的函数,调用的函数不需要加()

3.案例2(多页下载):电影天堂

需求:一个item包含多级页面的数据

  1. 创建项目:切换到项目存放目录,创建项目。

    1
    2
    3
    cd C:\Users\wuhen\Desktop

    scrapy startproject dytt
  2. 创建爬虫文件:进入爬虫存储文件,创建爬虫。

    1
    2
    3
    cd dytt/dytt/spiders

    scrapy genspider dytt_spider https://www.dyttcn.com/dongzuopian/list_1_1.html
  3. 爬虫运行:

    1
    2
    # 运行代码
    scrapy crawl hsw_spider
  4. 定义数据结构:在items.py编写

    1
    2
    3
    4
    5
    6
    7
    8
    import scrapy


    class DyttItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name = scrapy.Field()
    src = scrapy.Field()
  5. 编写爬虫:打开项目,检查hsw_spider.py的name、allowed_domains、start_urls,编写初步的爬虫.(注意meta传参)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    import scrapy
    from dytt.items import DyttItem


    class DyttSpiderSpider(scrapy.Spider):
    name = "dytt_spider"
    allowed_domains = ["www.dyttcn.com"]
    start_urls = ["https://www.dyttcn.com/dongzuopian/list_1_1.html"]

    def parse(self, response):
    # 要第一页的名字 和 第二页的图片
    name_list = response.xpath('//table[@class="tbspan"]//a[@class="ulink"][2]/text()')
    href_list = response.xpath('//table[@class="tbspan"]//a[@class="ulink"][1]/@href')


    for i in range(len(name_list)):
    name = name_list[i].extract()
    href = href_list[i].extract()

    # 第二页的地址
    url = 'https://www.dyttcn.com' + href

    # 访问第二页链接
    yield scrapy.Request(url=url,callback=self.parse_second,meta={'name':name}) # meta强行转换成字典


    def parse_second(self,response):
    # 若没有数据,修改xpath
    src = response.xpath('//div[@id="Zoom"]/div[1]/img/@src').extract_first()
    name = response.meta['name']

    movie = DyttItem(name=name,src=src)
    yield movie
  6. 管道文件:在pipelines.py下,处理下载的数据。

    在settings.py打开:

    1
    2
    3
    ITEM_PIPELINES = {
    "dytt.pipelines.DyttPipeline": 300,
    }

    注:只能是open_spider和close_spider。写入时只能是字符串对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class DyttPipeline:
    def open_spider(self,spider):
    self.fp = open('movie.json','w',encoding='utf-8')

    def process_item(self, item, spider):
    self.fp.write(str(item))
    return item

    def close_spider(self,spider):
    self.fp.close()

4.CrawlSpider

1.概念

  1. 继承自scrapy.Spider

  2. 独门秘笈

    • CrawlSpider可以定义规则,再解析html内容的时候,可以根据链接规则提取出指定的链接,然后再向这些链接发送请求
    • 所以,如果有需要跟进链接的需求,意思就是爬取了网页之后,需要提取链接再次爬取,使用CrawlSpider是非常合适的
  3. 提取链接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    链接提取器,在这里就可以写规则提取指定链接
    scrapy.linkextractors.LinkExtractor(
    allow = (), # 正则表达式 提取符合正则的链接
    deny = (), # (不用)正则表达式 不提取符合正则的链接
    allow_domains = (), # (不用)允许的域名
    deny_domains = (), # (不用)不允许的域名
    restrict_xpaths = (), # xpath,提取符合xpath规则的链接
    restrict_css = () # 提取符合选择器规则的链接
    )
  4. 模拟使用

    • 正则用法:links1 = LinkExtractor(allow=r’list_23_\d+.html’)
    • xpath用法:links2 = LinkExtractor(restrict_xpaths=r’//div[@class=”x”]’)
    • css用法:links3 = LinkExtractor(restrict_css=’.x’)
  5. 提取连接

    1
    link.extract_links(response)
  6. 注意事项

    • callback只能写函数名字符串, callback=’parse_item’

    • 在基本的spider中,如果重新发送请求,那里的callback写的是 callback=self.parse_item

      **注:**follow=true 是否跟进 就是按照提取连接规则进行提取

2.案例:读书网

  1. 创建项目

    1
    2
    3
    cd C:\Users\wuhen\Desktop

    scrapy startproject readbook
  2. 创建爬虫文件

    1
    2
    3
    cd readbook/readbook/spiders

    scrapy genspider -t crawl read https://www.dushu.com/book/1188.html
  3. 定义数据结构:在items.py编写

    1
    2
    3
    4
    5
    class ReadbookItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    name = scrapy.Field()
    src = scrapy.Field()
  4. 编写爬虫:read.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    import scrapy
    from scrapy.linkextractors import LinkExtractor
    from scrapy.spiders import CrawlSpider, Rule

    from readbook.items import ReadbookItem


    class ReadSpider(CrawlSpider):
    name = "read"
    allowed_domains = ["www.dushu.com"]
    start_urls = ["https://www.dushu.com/book/1188_1.html"]

    rules = (
    Rule(LinkExtractor(allow=r"/book/1188_\d+\.html"),
    callback="parse_item",
    follow=False),
    )

    def parse_item(self, response):
    img_list = response.xpath('//div[@class="bookslist"]//img')

    for img in img_list:
    name = img.xpath('./@alt').extract_first()
    src = img.xpath('./@data-original').extract_first()

    book = ReadbookItem(name=name,src=src)

    yield book

  5. 管道文件:在settings.py打开管道。在pipelines.py下,处理下载的数据。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class ReadbookPipeline:

    def open_spider(self,spider):
    self.fp = open('book.json','w',encoding='utf-8')

    def process_item(self, item, spider):
    self.fp.write(str(item))
    return item

    def close_spider(self,spider):
    self.fp.close()

  6. 创建数据库与表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    create database spider01 charser=utf8;

    use spider01

    create table book(
    id int primary key auto_increment,
    name varchar(128),
    src varchar(128)
    );
  7. 连接数据库:在settings.py任意位置输入

    1
    2
    3
    4
    5
    6
    7
    # 数据库名字
    DB_HOST = "localhost"
    DB_PORT = 3306
    DB_USER = "root"
    DB_PASSWORD = "root"
    DB_NAME = "spider01"
    DB_CHARSER = "utf8"
  8. 管道处理数据:在pipelines.py下(注意安装pymysql)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    class ReadbookPipeline:

    def open_spider(self,spider):
    self.fp = open('book.json','w',encoding='utf-8')

    def process_item(self, item, spider):
    self.fp.write(str(item))
    return item

    def close_spider(self,spider):
    self.fp.close()

    # 加载settings文件
    from scrapy.utils.project import get_project_settings
    import pymysql

    class MysqlPipeline:

    def open_spider(self, spider):
    settings = get_project_settings()
    self.host = settings['DB_HOST']
    self.port = settings['DB_PORT']
    self.user = settings['DB_USER']
    self.password =settings['DB_PASSWORD']
    self.name =settings['DB_NAME']
    self.charset =settings['DB_CHARSER']

    self.connect()

    def connect(self):
    self.conn = pymysql.connect(
    host=self.host,
    port=self.port,
    user=self.user,
    password=self.password,
    db=self.name,
    charset=self.charset
    )
    self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
    sql = 'insert into book(name,src) values("{}","{}")'.format(item['name'],item['src'])
    self.cursor.execute(sql)
    self.conn.commit()
    return item

    def close_spider(self, spider):
    self.cursor.close()
    self.conn.close()

5.日志信息与日志级别

  1. 日志级别:

    1
    2
    3
    4
    5
    6
    7
    8
    CRITICAL:	严重错误
    ERROR: 一般错误
    WARNING: 警告
    INFO: 一般信息
    DEBUG: 调试信息

    1.从下到上级别越高
    2.默认的日志等级是DEBUG,只要出现了DEBUG或者DEBUG以上等级的日志那么这些日志将会打印
  2. settings.py文件设置:

    1
    2
    3
    4
    5
    LOG_FILE : 将屏幕显示的信息全部记录到文件中,屏幕不再显示,注意文件后缀一定是.log
    LOG_FILE='logdemo.log'

    LOG_LEVEL : 设置日志显示的等级,就是显示哪些,不显示哪些
    LOG_LEVEL='WARNING'

6.scrapy的post请求

1.方法

1
2
3
4
5
6
7
8
(1)重写start_requests方法:
def start_requests(self)
(2) start_requests的返回值:
scrapy.FormRequest(url=url, headers=headers, callback=self.parse_item, formdata=data)
url: 要发送的post地址
headers:可以定制头信息
callback: 回调函数
formdata: post所携带的数据,这是一个字典

2.案例:百度翻译

  1. 创建项目

    1
    2
    3
    cd C:\Users\wuhen\Desktop

    scrapy startproject post_spider
  2. 创建爬虫

    1
    2
    3
    cd post_spider/post_spider/spiders

    scrapy genspider postDemo https://fanyi.baidu.com/sug
  3. 编写爬虫:post请求没有参数,则请求无意义,所以start_urls无用,parse方法无用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import scrapy
    import json

    class PostdemoSpider(scrapy.Spider):
    name = "postDemo"
    allowed_domains = ["fanyi.baidu.com"]
    # post请求没有参数,则请求无意义,所以start_urls无用,parse方法无用

    def start_requests(self):
    url = 'https://fanyi.baidu.com/sug'

    data = {
    'kw':'final'
    }

    yield scrapy.FormRequest(url=url,formdata=data,callback=self.parse_second)

    def parse_second(self,response):
    content = response.text
    obj = json.loads(content)
    print(obj)

7.代理

  1. 到settings.py中,打开一个选项

    1
    2
    3
    DOWNLOADER_MIDDLEWARES = {
    'postproject.middlewares.Proxy': 543,
    }
  2. 到middlewares.py中写代码

    1
    2
    3
    def process_request(self, request, spider):
    request.meta['proxy'] = 'https://113.68.202.10:9999'
    return None