爬虫

正则表达式

使用一些特殊符号的组合去字符串中筛选出符合条件的文本数据
# 正则表达式是一门独立的语言


前戏
# 使用python代码完成用户输入手机号的校验
    1.必须是纯数字
    2.只能是13 14 15 17 18 19开头
    
    
'''利用python编写'''
phone = input('please input your number>>>:').strip()
# 1.先判断用户输入的是否是纯数字
if phone.isdigit():  # isdigit判断字符串中是否是纯数字
    # 2 判断长度
    if len(phone) == 11:
        # 3.再判断是否是正常的电话开头
        if phone.startswith('13') or phone.startswith('14') or phone.startswith('15') or phone.startswith(
                '16') or phone.startswith('17') or phone.startswith('18') or phone.startswith('19'):
            print('是一个正常的手机号')
        else:
            print('请输入正确的手机号')
    else:
        print('手机号只能是11位')
else:
    print('必须是纯数字')
    
    
'''利用正则编写'''
import re
phone_number = input('please input your phone number : ')
if re.match('^(13|14|15|18)[0-9]{9}$',phone_number):
        print('是合法的手机号码')
else:
        print('不是合法的手机号码')

字符组

在线测试正则表达式:http://tool.chinaz.com/regex/

在"同一个位置"可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示
[0-9]
[a-z]
[A-Z]
一次只获取一个字符匹配
[0-7a-fA-O]  匹配数字0-7或者小写字母a-f或者A-O

特殊符号

.		匹配除换行符以外的任意字符
\d		匹配数字
^		匹配字符串的开头
$		匹配字符串的结尾
a|b		|表示"或"
()		仅仅是给正则表达式分组(不影响匹配)
[^]		匹配除了字符组中字符的所有字符"非"

量词

# 量词只能跟在表达式的后面,不能单独出现  作用就是增加匹配的次数
*		重复零次或更多次
+		重复一次或更多次
?		重复零次或一次
{n}		重复n次
{n,}	重复n次或更多次
{n,m}	重复n到m次
"""
正则表达式默认都是贪婪匹配的,即尽可能往多的去匹配
"""

正则表达式练习

参考博客内容:
https://www.cnblogs.com/Dominic-Ji/articles/11109067.html#_label10

贪婪匹配与非贪婪匹配

# 正则表达式默认情况下都是贪婪匹配
练习
待匹配的文本
	<script>hello world!</script>
正则表达式
	<.*>	# 贪婪匹配
结果
	全部一次性匹配
    
# 非贪婪匹配
	只需要在量词后面加上一个问号即可
待匹配的文本
	<script>hello world!</script>
正则表达式
	<.*?>	# 非贪婪匹配
结果
	<script>
	</script>

复杂正则解读

^[1-9]\d{13,16}[0-9x]$
^[1-9]\d{14}(\d{2}[0-9x])?$
^([1-9]\d{16}[0-9x]|[1-9]\d{14})$	
"""
针对一些比较复杂的正则表达式,我们完全没必要自己书写
	比如筛选手机号 身份证号 电话号等,直接百度网上有很多现成的直接拿来使用即可,不要重复的造轮子
"""

转义符

一些字母与\的组合 会产生特殊的含义
1.在python中我们习惯在字符串的前面加字母r取消转义
	res = r'E:jason\res\today'
2.在正则表达式中还可以使用\取消转义
	\\n表示匹配字符\n

re模块

如果我们想在python中使用正则表达式,需要借助于内置模块re(不需要下载)

import re
re.findall()  # 匹配符合条件的所有内容并支持分组优先展示
re.serach()  # 只要匹配到一个符合条件的就自动结束
re.match()  # 从字符串的开头开始匹配如果不满足后续直接结束

网络请求方法

1.get请求
	朝别人索要数据
    eg:
        浏览器地址栏输入网址回车,其实就是索要该网址对应的数据
        
2.post请求
	朝别人提交数据
    eg:
        用户的注册登录,其实就是将用户名和密码提交给服务端	

前端三剑客

HTML
	仅仅是用来构建网页的骨架
CSS
	用来调节HTML样式
JavaScript
	用来做动态效果

HTML

构造网页的骨架,我们使用浏览器看到的花里胡哨的页面背后其实就是由HTML组成的

网页文件的后缀名一般情况下都是.html

HTML其实就是一堆标签
	h3就表示标题标签
    a就表示连接标签
    img就表示图片标签
# 我们用浏览器肉眼看到的所有的花里花哨的内容其实内部都是一堆HTML标签

HTML标签文档结构

<html>
	<head></head>
    <body></body>
</html>
# head内的内容不是给人看的,大部分是给浏览器看的
# body内的内容就是浏览器展示给用户看到的内容


HTML标签分类
	1.双标签(有头有尾)
    	  <body></body>
        2.自闭和标签
    	  <img/>
# 针对双标签内部支持嵌套

HTML注释

<!--注释内容-->

head内常用标签(了解)

title	网页标题
link	导入外部css文件
script	导入外部js文件,还可以直接在内部书写js代码
style   内部书写css
meta	网页源信息

body内常用标签

# 标题标签
h1~h6

# 普通标签
<s>删除线</s>
<i>斜体</i>
<u>下划线</u>
<b>加粗</b>

# 段落标签
<p>20岁超越30岁、40岁、50岁人的成就!</p>

# 换行
<br>

# 分割线
<hr>

"""
为什么有些标签独占一行,有些标签可以多个在一行?
		1.块儿级标签
			独占浏览器窗口一行
				h1~h6
				p
				
		2.行内标签
			自身文本多大就占多大
				s、i、u、b
"""

特殊符号

&nbsp;  	空格
&gt;		大于
&lt;		小于
&yen;		羊角符
&amp;		&
&copy;		©
&reg;		®

常见标签

# 链接标签a
	href
    	1.存放链接地址 点击即可跳转
        2.存放其他标签的id值 点击定位到相应位置
    target
    	控制是否在当前页面跳转还是新建一个标签页打开
    	_self	默认在当前页跳转
        _blank  默认新建标签页跳转
        
# 图片标签img
	src	
    	存放图片的路径
        	既可以是网络的地址也可以是本地的地址
    alt
    	图片加载不出来之后显示的提示信息
    title
    	鼠标悬浮在上面自动提示的内容
    width
    	调整图片的宽度
    height
    	调整图片的高度
    # 注意宽度与高度调整一个另外一个自动等比例缩放 如果两个都调可能会导致图片的失真
    
# div标签与span标签
	div是块儿级标签
        span是行内标签
    """
    div和span都是用来做网页的前期布局使用
    	div类似于是个区域,当我们在构思网页的时候可以先用div划定区域
    	span类似于普通文本区域,划定之后将来就用来填写普通文本
    """
 
标签之间可以相互嵌套但是需要满足以下几点	
	1.只有块儿级标签可以块儿级标签和行内标签
    	p标签虽然是块儿级标签但是只能嵌套行内标签
        2.行内标签只能嵌套行内标签

标签的两大重要属性(掌握)

所有的标签都可以有class和id属性
	id
    	类似于是标签的身份证号,在同一个html文件内id不能重复
 	class
    	类似于是标签的分类,多个标签可以有相同的class值
        表示同属于一个类,一个标签也可以有多个class值
"""
id和class都是为了更加方便快捷的查找和操作标签
	id一对一的查找和操作
	而class则是分类查找和操作
"""

列表标签

无序列表(掌握)
    <ul>
        <li>111</li>
        <li>222</li>
        <li>333</li>
    </ul>
    # 原生的很丑但是通过css调整之后非常的实用,一般情况下有规则的排列都是用的无序列表
    
有序列表
    <ol>
        <li>111</li>
        <li>222</li>
        <li>333</li>
    </ol>
    
标题列表
    <dl>
      <dt>标题1</dt>
      <dd>内容1</dd>
      <dt>标题2</dt>
      <dd>内容1</dd>
      <dd>内容2</dd>
    </dl>

表格标签(掌握)

<table>
        <thead></thead>		# 表头(字段名称)
        <tbody></tbody>		# 表单(真正数据)
</table>

<tr>  # 表示一行内容
<th>  # 加粗文本(一般情况下用在字段名)
<td>  # 普通文本(一般情况下用在数据上)


<table border="1">
        <thead>
            <tr>
                <td>id</td>
                <td>username</td>
                <td>password</td>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>1</td>
                <td>jason</td>
                <td>123</td>
            </tr>
            <tr>
                <td>2</td>
                <td>tony</td>
                <td>123</td>
            </tr>
            <tr>
                <td>3</td>
                <td>jack</td>
                <td>222</td>
            </tr>
        </tbody>
</table>

form表单

"""获取用户数据并发送给后端服务器"""
input标签
	type属性
    	text		普通文本
        password	密文显示
        email		邮箱格式
        date		日期格式
	radio		单选框
        checkbox	多选框
        file		上传文件
    	submit		触发提交数据的动作
        reset		重置
        button		普通按钮
   
select标签(下拉框)
	一个个的选项就是一个个的option标签
    
textarea标签(大段文本框)
"""
针对form表单其实还有很多内容,但是我们无需再过多了解
后续如果遇到再讲解
"""

爬虫简介

1.什么是互联网?
	互联网是由网络设备(网线,路由器,交换机,防火墙等等)和一台台计算机连接而成,像一张网一样
    
2.互联网建立的目的?
	互联网的核心价值在于数据的共享/传递:数据是存放于一台台计算机上的,而将计算机互联到一起的目的就是为了能够方便彼此之间的数据共享/传递,否则你只能拿U盘去别人的计算机上拷贝数据了。

3.什么是上网?
	我们所谓的上网便是由用户端计算机发送请求给目标计算机,将目标计算机的数据下载到本地的过程
    
4.爬虫要做的是什么?
	不再借助于浏览器软件访问数据,而是直接通过代码模拟请求获取数据并解析筛选出我们需要的部分
    
如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个猎物,而爬虫程序就是一只小蜘蛛,沿着蜘蛛网抓取自己想要的猎物/数据

# 在互联网的世界里没有绝对的安全

	互联网中最有价值的便是数据,比如天猫商城的商品信息,链家网的租房信息,雪球网的证券投资信息等等,这些数据都代表了各个行业的真金白银,可以说,谁掌握了行业内的第一手数据,谁就成了整个行业的主宰,如果把整个互联网的数据比喻为一座宝藏,那我们的爬虫课程就是来教大家如何来高效地挖掘这些宝藏,掌握了爬虫技能,你就成了所有互联网信息公司幕后的老板,换言之,它们都在免费为你提供有价值的数据
    
    
"""
作为一名数据分析师,我们学习爬虫的目的仅仅是为了更加快速方便的获取浏览器可以直接访问到的数据
我们仅仅是用爬虫将数据进行筛选和整合提高工作效率
"""

requests模块

"""
1.使用浏览器访问网站
	1.发送请求
	2.服务端接收请求
		请求类似于主动跟别人说话
	3.服务端返回相应的响应
		响应类似于别人回应你的话(也可以不理你)
	4.浏览器接收到相应的响应解析成花里胡哨的页面展示给用户看
	
2.使用爬虫代码访问网站
	1.代码模拟浏览器发送请求
	2.服务端接收请求
	3.服务端返回相应的响应
	4.爬虫接收服务端返回的响应通过代码筛选出需要的数据内容并保存下来
	
***********************************************
基于网络传输数据,数据都是二进制格式
在python中也可以是bytes类型
***********************************************
"""
下载
	pip3 install requests
    # 换源下载
  
导入
	import requests
    
使用
	requests.get(url)
        requests.post(url)
    ...
    # 朝括号内的网址发送响应的网络请求
    
    
"""
URL
	统一资源定位符(你可以理解为是网址)
	由于网络上面的数据非常非常的多,如何在网络上准确无误的查找到我们需要的页面内容呢?就需要使用到URL
"""
import requests

# 朝百度发送get请求获取百度首页
res = requests.get('https://www.baidu.com')  # 类似于你在浏览器地址栏里面输入网址回车
# print(res.text)  # 获取返回的字符串数据
res.encoding = 'utf8'  # 修改数据的字符编码
with open(r'baidu.html', 'w', encoding='utf8') as f:
     f.write(res.text)  # 自动将二进制数据按照utf8编码解码成字符串

HTTP协议

规定了浏览器与服务端之间数据交互的各项原则
如果你在开发网站的时候不遵循HTTP协议,那么使用浏览器就无法正常的访问到你的网站

1.四大特性
	1.基于TCP、IP作用于应用层之上的协议(你们了解即可)
    2.基于请求响应
    	基于HTTP协议交互数据的服务端从来不会主动给你发消息
        必须你先请求它才会被动的做出响应
    3.无状态
    	不保存用户的状态
    	见了千百遍,也当是初见
    4.无/短连接
2.数据格式
	请求数据格式
    	请求首行(请求方法 协议版本)
        请求头(一大堆k:v键值对)		
        
        请求体
        	(发送post请求 敏感的数据都是放在请求体里面的)
    		(发送get请求 数据不是存放在请求体里面的)
            get请求携带额外的数据是直接放在url的后面
            	url?username=jason&password=123
    响应数据格式
    	响应首行(响应状态码)
        响应头(一大堆k:v键值对)		
        
        响应体(里面存放的就是浏览器要展示给用户看的数据)

3.响应状态码
	用数字来表示一大段中文意思,简化识别难度(类似于暗号)
    1XX:服务端已经接收到你的数据正在处理,你可以继续提交或者等待
    2XX:请求成功,服务端返回了相应的响应(200 OK)
    3XX:重定向(有时候访问网站点着点着突然跳转到登录页面 访问A却变成了B)
    4XX:403当前没有资格访问该资源,404请求资源不存在
    5XX:服务器内部错误
    """
    有很多公司在HTTP响应状态码的基础之上还会自己定制自己独有的状态码
    1000020		防火墙出问题
    ...
    """

防爬措施

1.校验你是否是一个浏览器
	通过查看请求头中是否含有一个能够标识浏览器身份的K:V键值对
    User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
    破解措施
    	就是在我们的请求头中带上上述的键值对即可
        requests.get(url,headers={k1:v1,k2:v2...})

requests更多操作

# 携带请求头
res = requests.get('https://dig.chouti.com/',
                   # 携带请求头数据
                   headers={
                       "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
                   }
                   )

# get请求携带额外的参数
res = requests.get('https://www.baidu.com/s',
                   # get请求携带参数
                   params={
                       'wd': '美女'
                   },
                   # 加上请求头User-Agent
                   headers={
                       "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
                   }
                   )

# 携带cookie数据
res = requests.get(url,cookies={k1:v1,...})

cookie与session

HTTP协议四大特性中有一个特性是无法保存用户状态,但是我们现在很多软件都需要保存用户状态

Cookie
	保存在客户端浏览器上面的K:V键值对(可以有多个)
        
Session
	保存在服务端上面的用户相关的数据
    eg:当用户登录成功之后返回给浏览器一个随机字符串
        之后浏览器访问该服务端就带着这个随机字符串
        服务端校验随机字符串是否正确从而识别身份
# Session的工作需要依赖于Cookie  
"""浏览器虽然可以保存cookie但是也可以拒绝保存cookie"""

利用cookie模拟登录

# 使用代码模拟登录
华华手机为例
	1.先用浏览器登录
    	查看登录的接口地址(查找数据往哪个地址提交的)
        具体思路:
            1.打开登录页面
            2.随意填写用户名和密码
            3.右键打开浏览器终端点击network查看请求
基于上述思路成功获取到接收用户数据的地址:http://www.aa7a.cn/user.php
也就是说我们一会儿通过代码直接朝上述地址发送请求即可

	2.由于post请求数据是放在请求体里面的
    	查看华华手机登录接口请求体数据格式
        具体思路:
            1.打开登录页面
            2.随意填写用户名和密码
            3.右键打开浏览器终端点击network查看请求
        username: 18817628568
        password: dsadsadasd
        captcha: exwt
        remember: 1
        ref: http://www.aa7a.cn/category-39-b0.html
        act: act_login
基于上述思路成功获取到请求体数据格式,也就意味着一会儿我们通过代码模仿构造出一样的数据格式提交即可

# requests模块发送post请求携带请求体数据
requests.post(url,data={k:v,...})

如何判定用户是否是登录状态?
	页面右上角显示的是登录注册还是用户名
    	如果是登录注册说明没有登录
        如果是用户名表示登录
  
import requests

# res = requests.post(
#     'http://www.aa7a.cn/user.php',
#     # 请求头
#     headers={
#         "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
#     },
#     # 请求体数据
#     data={
#         'username': '616564099@qq.com',
#         'password': 'lqz12333333',
#         'captcha': 'exwt',
#         'remember': 1,
#         'ref': 'http://www.aa7a.cn/',
#         'act': 'act_login'
#     }
# )
# 获取服务端返回的cookie数据
# my_cookies = res.cookies.get_dict()
# print(my_cookies)
"""
用户名密码正确的情况下
{
'ECS[password]': '4a5e6ce9d1aba9de9b31abdf303bbdc2', 
'ECS[user_id]': '61399', 
'ECS[username]': '616564099%40qq.com', 
'ECS[visit_times]': '1', 
'ECS_ID': '65656a64e702189c8dfacb53a85499d9812ac86f'
}

用户名或密码错误的情况下
{'ECS[visit_times]': '1', 'ECS_ID': 'e64fb781313753b0f99731e6d9dab8a70cf39885'}
"""
# 携带cookie访问网站 验证是否有效
res = requests.get('http://www.aa7a.cn/',
                   headers={
                       "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
                   },
                   cookies={
                       'ECS[password]': '4a5e6ce9d1aba9de9b31abdf303bbdc2',
                       'ECS[user_id]': '61399',
                       'ECS[username]': '616564099%40qq.com',
                       'ECS[visit_times]': '1',
                       'ECS_ID': '65656a64e702189c8dfacb53a85499d9812ac86f'
                   }
                   )
# 如何校验是否登录呢?
if '616564099@qq.com' in res.text:
    print("登录状态访问")
else:
    print("未登录状态访问")

防爬措施

1.referer  用来标记当前请求从何而来
	eg:
        图片防盗链
        当请求发送到服务端之后,服务端可以先校验请求头里面的referer鉴别当前请求是否是本网站发出的,如果是那么直接给相应的资源如果不是那么可以拒绝

获取大文件数据

当我们基于网络请求到的数据量特别大的情况下
如果我们直接使用res.text或者res.content可能会导致计算机内存的溢出(爆了)

#stream参数:一点一点的取,比如下载视频时,如果视频100G,用response.content然后一下子写到文件中是不合理的

import requests

res=requests.get('https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo-transcode/1767502_56ec685f9c7ec542eeaf6eac93a65dc7_6fe25cd1347c_3.mp4',
                      stream=True)

with open('b.mp4','wb') as f:
    for line in res.iter_content():
        f.write(line)

json格式

# 内置模块无需下载
json格式是用来实现不用语言之间的数据传输
最常用的就是python与JavaScript之间的前后端数据交互

json格式长的跟我们python里面的字典非常相似
只不过json格式的数据内部必须都是双引号

d = {"username": "jason", "password": "123"}


import json
# 将字典d转换成json格式的字符串
res = json.dumps(d)  # 序列化
# print(res,type(res))
# 将json格式的字符串转换成python中的字典
res1 = json.loads(res)  # 反序列
print(res1,type(res1))


"""
序列化:将python中的数据类型转换成json格式的字符串
反序列化:将json格式的字符串转换成python中的数据类型
"""
# 前后端数据交互一般都是采用json格式

代理池

1.IP代理池
	ip地址:每一台接入互联网的计算机都会有一个ip地址,ip地址相当于是身份证号,我们通过ip地址就可以明确的查找到互联网上面的某一台计算机
     防爬措施
    	服务端有时候也会校验IP地址
        	在规定的一个时间范围内,某一个ip地址访问网站的次数不能超过限定的次数,如果超过了直接封禁(2小时、半个月、终身)
        解决措施
        	采用IP代理池
            	免费
                收费
        	http://www.taiyanghttp.com/free/
   		代码实现
        	import requests
            proxies = {
                'http': '221.10.217.26:4261',
                'http': '110.88.31.173:4278',
                'http': '218.6.105.99:4206',
            }
            respone = requests.get('https://www.12306.cn',
                                   proxies=proxies)
            print(respone.status_code)
            
2.cookie代理池
	服务端有时候也会校验cookie数据
            在规定的一个时间范围内,某一个cookie访问网站的次数不能超过限定的次数,如果超过了直接封禁账号(2小时、半个月、终身)
        解决方案:
            先提前使用N多个账号登录该网站获取对应的cookie数据并保存起来
            之后每一次访问的是都随机携带一个cookie数据     

Beautiful Soup模块

可以帮助我们去html文档中筛选出我们需要的数据内容

它是一个第三方模块,需要你自己手动下载
pip3 install beautifulsoup4

该模块在查找数据的时候有四种解析器(四种不同的查找策略)
html.parse
lxml		# 推荐使用 需要下载
lxml.xml
html5lib

pip3 install lxml

# 参考文档
https://www.cnblogs.com/xiaoyuanqujing/articles/11805757.html
    
# 模拟网络请求获取到的页面html数据
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little 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>
"""
# 导入模块
from bs4 import BeautifulSoup

# 将需要筛选的数据填入
soup = BeautifulSoup(html_doc, 'lxml')
# print(soup.prettify())  # 格式化美化展示

# 查找页面上所有的a标签  结果是一个列表
# print(soup.find_all(name='a'))
# 查找第一个a标签里面的文本内容
# print(soup.a.text)
# 查找第一个a标签里面的属性名与属性值
# print(soup.find_all(name='a')[0].attrs)
# print(soup.a.attrs)  # 等价
# 查找第一个a标签里面的id值
# print(soup.a.attrs.get('href'))
# print(soup.a.attrs['href'])  # 等价
# 查找id是link1的标签
# print(soup.find(attrs={'id': 'link1'}))
# 查找class是sister的标签
# print(soup.find(attrs={'class': 'sister'}))
# print(soup.find_all(attrs={'class': 'sister'}))

# 扩展
# print(soup.find(id='link1'))
print(soup.find(class_='sister'))  # 如果跟python中的关键字冲突 需要在末尾加下划线

"""
find
    结果是符合筛选条件的第一个标签
find_all
    结果是所有符合筛选条件的标签,列表的形式
"""

防爬措施

1.校验是否是浏览器
	User-Agent
2.校验请求从何而来
	referer
3.IP代理池
	在规定的时间内同一个ip地址访问网站的次数不能超出上限
4.cookie代理池
	在规定的时间内同一个cookie访问网站的次数不能超出上限

bs4模块补充

# CSS选择器
1.如果想通过id查找标签
	#d1		>>>		id='d1'
2.如果想通过class查找标签
	.c1	    >>>      class='c1'
3.查看标签内部的标签(标签可以相互嵌套)
	<div>
    	<p>
        	<a></a>
        </p>
        <a></a>
    </div>
    查找div标签里面所有的后代a标签
    	div a  # 空格表示后代
    查看div标签里面儿子a标签
    	div>a  # >表示儿子

requests-html模块

1.该模块支持执行js代码,requests模块是不支持的
2.操作更加简单方便
3.与requests模块是同一个作者

下载 
	pip3 install requests-html
基本使用
	>>> from requests_html import session
    # 返回一个Response对象
    >>> r = session.get('https://python.org/')
    # 获取所有链接
    >>> r.html.links
    {'/users/membership/', '/about/gettingstarted/'}
    # 使用css选择器的方式获取某个元素
    >>> about = r.html.find('#about')[0]
    >>> print(about.text)
    About
    Applications
    Quotes
    Getting Started
    Help
    Python Brochure

爬取链家二手房数据

"""
1.在写爬虫程序的时候我们一定要有一个找寻规律的想法
    地区规律
        https://sh.lianjia.com/ershoufang/
        https://bj.lianjia.com/ershoufang/
        https://sz.lianjia.com/ershoufang/
    分页规律
    	https://sh.lianjia.com/ershoufang/
    	https://sh.lianjia.com/ershoufang/pg2/
    	https://sh.lianjia.com/ershoufang/pg3/
    	...
    	https://sh.lianjia.com/ershoufang/pgN/
2.在查找标签的时候我们有两种思路
	1.直接点名道姓的查找具体的标签
		链家网
	2.先获取标签所在的父标签之后再分析
		汽车之家
"""
针对后续我们会学习到的内容pandas模块,如果你想提前使用需要下载两个模块
pip3 install pandas
pip3 install openpyxl

# 代码不要频繁的执行 最好加上人为的延迟
import time
time.sleep(3)

爬取天气数据

"""
有时候页面上的数据并不是直接加载好的
而是通过后期js动态请求后端完成的实时加载
"""
http://tianqi.2345.com/wea_history/60010.htm
1.研究点击以往的数据 页面url不发生变化    
	数据是通过内部js代码动态请求
2.如何查看网页内部js代码
	在浏览器任意位置鼠标右键
    点击检查
    点击network
    再次发送请求
    查看js文件
    筛选出可疑的url,尝试着直接发请求查看响应内容
3.url规律
	http://tianqi.2345.com/Pc/GetHistory?areaInfo%5BareaId%5D=60010&areaInfo%5BareaType%5D=2&date%5Byear%5D=2020&date%5Bmonth%5D=12
4.朝上述url发送get请求获取json数据之后解析出天气数据


import requests


res = requests.get('http://tianqi.2345.com/Pc/GetHistory?areaInfo%5BareaId%5D=60010&areaInfo%5BareaType%5D=2&date%5Byear%5D=2020&date%5Bmonth%5D=11')
json_dict = res.json()  # 相当于是浏览器自动帮你解析数据
real_data = json_dict.get('data')
# print(real_data)

import pandas as pd
# 当需要从table标签中筛选出数据 使用pandas里面的方法最为方便
ret = pd.read_html(real_data)
df = ret[0]
df.to_excel(r'tianqi.xlsx')

爬取汽车之家

1.直接尝试发送get请求
2.使用bs4模块筛选数据
import requests
from bs4 import BeautifulSoup

# proxies = {
#     'http': '221.10.217.26:4261',
#     'http': '110.88.31.173:4278',
#     'http': '218.6.105.99:4206',
# }
res = requests.get('https://www.autohome.com.cn/news/',
                   # proxies=proxies
                   )
soup = BeautifulSoup(res.text, 'lxml')
# 先整体后局部
ul = soup.find(name='ul', class_='article')  # 先获取所有文章数据所在的ul标签
# 分析页面结构得知每一篇文章就是ul里面的一个个li标签
li_list = ul.find_all(name='li')  # [文章数据1,文章数据2,...]

# for循环依次获取每一篇文章所在的li标签之后筛选出需要的数据
for li in li_list:
    # 文章标题
    h3 = li.find(name='h3')
    if h3:
        print(h3.text)

selenium模块

它最初是一个测试工具,之所以拿来使用是因为它可以弥补requests模块无法执行js文件的短板

注意
    如果你想通过该模块操作你电脑上面的浏览器
    你需要提前下载好相关浏览器的驱动,针对不同的浏览器需要下载不同的驱动
    而我们开发一般都是使用谷歌浏览器,所以下载谷歌驱动即可
 
下载驱动的网址
    http://npm.taobao.org/mirrors/chromedriver/2.38/
    下载之后解压,将.exe的文件放到python解释器文件scripts文件夹内
    
下载模块
	pip3 install selenium

查找标签

# 1、find_element_by_id   根据id找
# span = bro.find_element_by_id('form')
# print(span)
# 2、find_element_by_link_text     根据链接名字找到控件(a标签的文字)
# a = bro.find_element_by_link_text('新闻').get_attribute('href')
# print(a)
# 3、find_element_by_partial_link_text   根据链接名字找到控件(a标签的文字)模糊查询
# a = bro.find_element_by_partial_link_text('123').text
# print(a)  # 类似于MySQL中的like模糊查询
# 4、find_element_by_tag_name       根据标签名
# 5、find_element_by_class_name     根据类名
# 6、find_element_by_name           根据属性名
# 7、find_element_by_css_selector   根据css选择器

案例

1.浏览器打开京东并搜索商品跳转到对应的页面
2.浏览器打开百度自动点击登录并输入用户名密码
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys

bro = webdriver.Chrome()
bro.get("http://www.baidu.com")  # 自动调用浏览器打开百度
bro.implicitly_wait(10)  # 先忽略

# 1、find_element_by_id   根据id找
# span = bro.find_element_by_id('form')
# print(span)
# 2、find_element_by_link_text     根据链接名字找到控件(a标签的文字)
# a = bro.find_element_by_link_text('新闻').get_attribute('href')
# print(a)
# 3、find_element_by_partial_link_text   根据链接名字找到控件(a标签的文字)模糊查询
# a = bro.find_element_by_partial_link_text('123').text
# print(a)  # 类似于MySQL中的like模糊查询
# 4、find_element_by_tag_name       根据标签名
# 5、find_element_by_class_name     根据类名
# 6、find_element_by_name           根据属性名
# 7、find_element_by_css_selector   根据css选择器
# 1.先找到搜索框标签
# input_ele = bro.find_element_by_id('key')
# # 2.在该input框内输入内容
# input_ele.send_keys('性感内衣')
# # 3.模拟键盘的enter键
# input_ele.send_keys(Keys.ENTER)

# 1.先查找登录的a标签
a_ele = bro.find_element_by_link_text('登录')
# 2.点击该标签
a_ele.click()
# 3.点击弹出框里面的用户名密码登录
a_html = bro.find_element_by_id('TANGRAM__PSP_11__footerULoginBtn')
a_html.click()
time.sleep(1)
# 4.查找获取用户用户名和密码的input框 分别输入内容
username_ele = bro.find_element_by_id('TANGRAM__PSP_11__userName')
username_ele.send_keys('15617628568')
password_ele = bro.find_element_by_id('TANGRAM__PSP_11__password')
password_ele.send_keys('jason123')
time.sleep(1)
# 5.查找登录按钮 点击登录
submit_ele = bro.find_element_by_id('TANGRAM__PSP_11__submit')
submit_ele.click()

time.sleep(10)
bro.close()  # 自动关闭浏览器页面

延时等待

"""
代码的运行速度是非常快的
但是有时候我们在打开网页的时候由于网速等各种原因导致页面还没有完全加载出来
但是代码已经运行到最后了,那么这种情况下会经常出现代码报错的情况
"""

显式等待和隐式等待
# 隐式等待:在查找所有元素时,如果尚未被加载,则等10秒
# browser.implicitly_wait(10)   表示等待所有,

# 显式等待:显式地等待某个元素被加载
# wait=WebDriverWait(browser,10)
wait.until(EC.presence_of_element_located((By.ID,'content_left')))

'''我们一般情况下都是使用隐式等待,你直接在代码上拷贝即可'''

异常处理

异常其实就是代码运行过程中产生了无法解决的问题从而导致整个程序的终止(bug)
错误的三个提示
	1.错误的位置
    2.错误的类型
    3.错误的原因
 
错误总共分为两大类
	语法错误
    	是不能够被容忍的,一旦出现了立刻修改
    逻辑错误
    	是可以被允许的

异常处理其实就是针对代码中可能会出现的逻辑错误,提前布局处理
try:
    可能会出错的代码
except 错误类型:
    解决措施
 
错误类型
	indexerror
    nameerror
    keyerror
   	# 万能异常
    exception
  
"""
异常处理的代码能尽量少使用就尽量少使用
并且可能会出错的代码也要做到尽可能的少
"""

获取标签数据

a_ele = bro.find_element_by_id('d1')

1.获取标签内部的文本
	a_ele.text
2.获取标签的属性数据
	a_ele.get_attribute('href')

常见操作

#模拟浏览器前进后退
browser.back()
browser.forward()

bro.execute_script(JS代码)

# 选项卡管理
# import time
# from selenium import webdriver
browser=webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.execute_script('window.open()')

print(browser.window_handles) #获取所有的选项卡
browser.switch_to_window(browser.window_handles[1])
browser.get('https://www.taobao.com')
time.sleep(3)
browser.switch_to_window(browser.window_handles[0])
browser.get('https://www.sina.com.cn')
browser.close()

selenuim模块补充

# 滑动验证
有一些网站需要用户点击滑动才可以进入或者访问
	解决方法1:
        使用代码破解,但是非常复杂不建议使用
    解决方式2:
        自己手动移动

cookie数据

# requests.cookies
# driver.get_cookies()

使用selenuim尝试爬取京东商品数据

"""
有时候页面上面的数据会出现懒加载现象
	只有当用户即将要滑动到该区域之后才会加载对应的内容
	比如img标签,如果有懒加载那么它的src和data-lazy-img
		不加载的时候存在data-lazy-img
		加载完成之后存在src
img = li.find_element_by_css_selector('.p-img a img').get_attribute('src')
    if not img:
        img_url = 'https:' + li.find_element_by_css_selector('.p-img a img').get_attribute('data-lazy-img')
        print(img_url)
    else:
        print(img)
"""
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()
driver.get('https://www.jd.com/')
driver.implicitly_wait(10)  # 使用隐式等待

# 查看输入框
input_ele = driver.find_element_by_id('key')
# 输入需要爬取的商品数据  这里可以使用输入框获取用户需要爬取的商品
input_ele.send_keys('手机')
# 按enter进入商品界面
input_ele.send_keys(Keys.ENTER)

li_list = driver.find_elements_by_css_selector('.gl-item')
for li in li_list:
    a = li.find_element_by_css_selector('.p-img a')
    if a:
        print(a.get_attribute('href'))
    img_url = li.find_element_by_css_selector('.p-img a img').get_attribute('src')
    if not img_url:
        img_url = 'https:' + li.find_element_by_css_selector('.p-img a img').get_attribute('data-lazy-img')

    i = li.find_element_by_css_selector('.p-price i')

    em = li.find_element_by_css_selector('.p-name a em')

    comment = li.find_element_by_css_selector('.p-commit a')
    print("""
    商品链接:%s
    商品图片:%s
    商品简介:%s
    商品价格:%s
    商品销量:%s
    """ % (a.text, img_url, i.text, em.text, comment.text))
"""
商品自定义
分页爬取
"""

openpyxl模块

"""
1.excel版本
	03版本之前
		文件后缀名是.xls
	03版本之后
		文件后缀名是.xlsx
		
2.能够操作excel表格的模块
	openpyxl
	xlrd,xlwt
		wlrd控制表格的读取
		xlwt控制表格的写入
	openpyxl模块针对03版本之前的表格文件兼容性较差
	xlrd,xlwt兼容03版本之前和之后的文件
	但是openpyxl是最近出来的比较火的操作excel表格的模块
"""
下载
	pip3 install openpyxl
 
参考文档
	https://openpyxl.readthedocs.io/en/stable/tutorial.html

生成表格文件

from openpyxl import Workbook

wb = Workbook()
# 创建工作簿
w1 = wb.create_sheet('我的工作簿1', index=0)
w2 = wb.create_sheet('我的工作簿2')
w3 = wb.create_sheet('我的工作簿3')

# 还可以修改工作簿名称
w1.title = 'MySheet01'

wb.save(r'aaa.xlsx')

写数据

# 写数据
# 方式1
# w1['A1'] = 123
# w2['B6'] = 666
# w3['D9'] = 999
# 方式2
# w1.cell(row=2, column=1, value=666)

# 写公式(公式前面的等号不能省略!)
# w1['A5'] = '=sum(A1:A2)'


# 一次性写入多个单元格数据
# 方式1
# w1['A1'] = '序号'
# w1['B1'] = '姓名'
# w1['C1'] = '年龄'
# w1['D1'] = '性别'
# for i in range(2,10):
#     w1['A%s'%i] = i - 1
#     w1['B%s'%i] = 'jason%s'%i
#     w1['C%s'%i] = i
#     w1['D%s'%i] = 'male'
# 方式2
# 写字段
w1.append(['id', 'name', 'age', 'gender', 'hobby'])
# 写数据
w1.append([1, 'jason', 18, 'male', 'read'])
w1.append([2, 'tony', 28, 'female', 'game'])
w1.append([3, 'kevin', 38, 'male', 'music'])

w1.append([1, 'alisa', 18, 'female'])
w1.append([5, 'male', 99, 'run'])
"""在填写数据的时候一定要确保位数一致,如果有缺失数据用空字符代替不要直接不写"""
wb.save(r'aaa.xlsx')

读数据

from openpyxl import load_workbook

wb = load_workbook(r'aaa.xlsx',data_only=True)
# 查看所有的工作簿名称
# print(wb.sheetnames)  # ['MySheet01', 'Sheet']
# 选择需要读取数据的工作簿
w1 = wb['MySheet01']  # 操作MySheet01工作簿

# 方式1
# print(w1['B2'])  # <Cell 'MySheet01'.B2>
# print(w1['B2'].value)  # jason
# 方式2
# print(w1.cell(row=2,column=3))  # <Cell 'MySheet01'.C2>
# print(w1.cell(row=2,column=3).value)  # 18

'''默认只能获取到公式'''
# 读取公式栏目数据
print(w1['A7'].value)  # =sum(A1:A3)
"""
要想读取公式计算之后的结果需要做下面两步操作
1.必须加一个参数
    data_only=True
    wb = load_workbook(r'aaa.xlsx',data_only=True)
2.必须人为操作一下excel表格
"""

openpyxl模块结束

from openpyxl import Workbook, load_workbook


# wb = Workbook()
#
# w1 = wb.create_sheet('MySheet')
# w1.append(['id','name','password'])
# w1.append([1,'jason','123'])
# w1.append([2,'kevin','234'])
# w1.append([3,'tom','666'])
#
#
#
# wb.save(r'a.xlsx')


wb = load_workbook(r'a.xlsx')
w1 = wb['MySheet']

# w1.rows获取一行行数据
# for row in w1.rows:
#     # print(row)  # (<Cell 'MySheet'.A1>, <Cell 'MySheet'.B1>, <Cell 'MySheet'.C1>)
#     for data in row:
#         print(data.value)

# w1.columns获取一列列数据
# for col in w1.columns:
#     # print(col)  # (<Cell 'MySheet'.A1>, <Cell 'MySheet'.A2>, <Cell 'MySheet'.A3>, <Cell 'MySheet'.A4>)
#     for c in col:
#         print(c.value)

print(w1.max_row)  # 获取数据总行数
print(w1.max_column)  # 获取表格列字段数量

图片验证码的破解思路

破解思路1:
    python图像识别模块
    	软件:Tesseract-ocr 
    	模块:pytesseract
    # https://blog.csdn.net/qq_38161040/article/details/90668765 
    """由于有现成的模块可以直接识别图片上面的文字,为了避免直接被识别所以图片验证码往往都设计的很模糊很抽象不容易识别"""
    
破解思路2:
    利用第三方服务平台(打码平台)
    # http://sb.daredian.cn/?spm=dm.pc@baidu
    
破解思路3:
    自己人工智能解决

Xpath选择器

本质也是用来帮助我查找html标签

# 模拟代码爬取下来的html数据
doc = '''
<html>
 <head>
  <base href='http://example.com/' />
  <title>Example website</title>
 </head>
 <body>
  <div id='images'>
   <a href='image1.html' a="xxx">Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
   <a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
   <a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
   <a href='image4.html' class='li'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
   <a href='image5.html' class='li li-item' name='items'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
   <a href='image6.html' name='items'><span><h5>test</h5></span>Name: My image 6 <br /><img src='image6_thumb.jpg' /></a>
  </div>
 </body>
</html>
'''
from lxml import etree

# from bs4 import BeautifulSoup
#
# soup = BeautifulSoup(doc,'lxml')
# 固定语句
html = etree.HTML(doc)

# 1 所有节点
# a = html.xpath('//*')  # 匹配所有标签
# 2 指定节点(结果为列表)
# a = html.xpath('//head')  # 通过标签名查找标签
# 3 子节点,子孙节点
# a = html.xpath('//div/a')  # 查找div内部儿子a
# a = html.xpath('//body/a')  # 无数据
# a = html.xpath('//body//a')  # 查找body所有的后代a
# # 4 父节点
# a=html.xpath('//body//a[@href="image1.html"]')  # 查找div内部所有后代a并且href必须是image1.html
# a=html.xpath('//body//a[@a="xxx"]')  # 查找div内部所有后代a并且a属性名对应的属性值必须是xxx
# a = html.xpath('//body//a[1]')  # 从1开始计数
# a = html.xpath('//body//a[1]/..')  # ..表示上一级

# # 也可以这样
# a=html.xpath('//body//a[1]/parent::*')
# # 5 属性匹配
# a=html.xpath('//body//a[@href="image1.html"]')
#
# # 6 文本获取
# a=html.xpath('//body//a[@href="image1.html"]/text()')
# a=html.xpath('//body//a/text()')  # 获取所有后代a里面的文本数据
#
# # 7 属性获取
# a = html.xpath('//body//a/@href')
# # # 注意从1 开始取(不是从0)
# a=html.xpath('//body//a[2]/@href')
# # 8 属性多值匹配
# #  a 标签有多个class类,直接匹配就不可以了,需要用contains
# a=html.xpath('//body//a[@class="li"]')
# a=html.xpath('//body//a[contains(@class,"li")]/text()')
# # 9 多属性匹配
# a=html.xpath('//body//a[contains(@class,"li") or @name="items"]')
# a=html.xpath('//body//a[contains(@class,"li") and @name="items"]/text()')
# # 10 按序选择
# a=html.xpath('//a[2]/text()')
# a=html.xpath('//a[2]/@href')
# # 取最后一个
# a=html.xpath('//a[last()]/@href')
# # 位置小于3的
# a=html.xpath('//a[position()<3]/@href')
# # 倒数第二个
# a=html.xpath('//a[last()-2]/@href')


# # 11 节点轴选择
# # ancestor:祖先节点
# # 使用了* 获取所有祖先节点
# a=html.xpath('//a/ancestor::*')
# # # 获取祖先节点中的div
# a=html.xpath('//a/ancestor::div')
# # attribute:属性值
a=html.xpath('//a[1]/attribute::*')
# # child:直接子节点
# a=html.xpath('//
# ['image6.html']a[1]/child::*')
# # descendant:所有子孙节点
# a=html.xpath('//a[6]/descendant::*')
# # following:当前节点之后所有节点
# a=html.xpath('//a[1]/following::*')
# a=html.xpath('//a[1]/following::*[1]/@href')
# # following-sibling:当前节点之后同级节点
# a=html.xpath('//a[1]/following-sibling::*')
# a=html.xpath('//a[1]/following-sibling::a')
# a=html.xpath('//a[1]/following-sibling::*[2]/text()')
# a=html.xpath('//a[1]/following-sibling::*[2]/@href')
print(a)

知乎登录案例

1.知乎PC端必须登录之后才可以访问
2.研究用户名密码登录
	通过network识别到登录的后台地址
		https://www.zhihu.com/api/v3/oauth/sign_in
3.研究请求体数据格式
	通过network查看post请求的请求体数据格式
		发现请求体数据是被加密处理
    # 问题:意味着我们无法构造出请求体数据
    """
    1.我们不知道加密的算法是什么 也不知道是否加盐处理
    2.我们也不知道参与加密的数据格式和数据数量
    """
4.我们点击登录按钮查看请求体发现是加密的数据 
	也就意味着在发送给服务端之前数据就已经被加密了
    说明肯定是在客户端浏览器做了该加密操作
    而在前端能够编写出类似于编程的语言只有js可以
	我们只需要在浏览器上查找到该js代码即可破解请求体加密数据套路
5.查找加密相关的js代码
	设计到加密一般都会使用一个关键字encrypt
     也就意味着我们需要从很多文件中筛选出含有上述关键字的代码
     然后自己判断到底是哪个
6.分析文件查找相应代码
	client_id      用户id(固定值)
    grant_type     验证方式(固定值)
    timestamp      时间戳*1000,去尾
    source		   (固定值)
    signature	   签名(js加密,变动)
    username	   用户名
    password	   密码
    captcha		   验证码
    lang		   验证码方式(固定值)
    utm_source	   (固定值)
    ref_source	   (固定值)other_https://www.zhihu.com/signin?next=%2F
7.针对signature加密需要再次去js文件中筛选出相应的代码

红薯网小说案例

https://www.hongshu.com/content/3052/3317-98805.html
1.该页面鼠标左键右键都无法正常使用
	目的就是不想让你用鼠标左键选中拷贝,右键调出终端
	针对终端:F12即可
    针对拷贝:让浏览器禁止所有的js加载(可能有用可能无用)
2.研究小说内容是否是直接加载到页面上的
	小说内容通过查看HTML文档发现存在缺失
    而展示到页面上之后却完整了
3.还是需要查找相应的js文件
	{code: 119, msg: "获取章节内容成功", key: "36716822"}
	content是加密内容 非常可疑
     other也是加密的内容 非常可疑
     由于上述内容是通过发送post请求获取 所以我们查找请求体
    method: getchpcontent
    bid: 3052
    jid: 3317
    cid: 98805
4.服务端给的是加密的数据但是展示出来之后却又是明文,说明解析过程肯定发生在浏览器上,而能够完成解析的语言前端只有js可以
	查找解密相关的js代码
    # 解密相关一般都会出现关键字decrypt
5.从sources中查找含有关键字decrypt的js代码
	找到了data和other相关的js代码
6.将最为关键的解析数据的代码拷贝到浏览器console界面执行
	data.content = utf8to16(hs_decrypt(base64decode(data.content), key))
    发现结果就是文章内容的一部分
7.将代码执行之后的结果拷贝到一个新建的html文件内让浏览器展示
	将展示之后的结果拷贝再次放入html文件内
    再次展示发现还是缺少文章内容
8.将other相关的代码拷贝到浏览器console执行
	data.other = utf8to16(hs_decrypt(base64decode(data.other), key))
    结果是一串js代码
9.我们应该怀疑该js代码就是用来加载缺失数据的部分
	将上述js代码拷贝到一个js文件中
    然后在展示一部分内容的html页面上引入该js文件
10.通过研究页面发现所有缺失的文字内容都在css代码中
	通过自己书写js代码获取css文字
    动态插入到页面上完成数据的补全操作

爬虫框架之Scrapy

框架
	类似于提前已经帮你搭建好了基础的架构
    你只需要往框架固定的地方填写固定的内容就可以实现相应的功能

下载
	pip3 install scrapy
    
# 上述下载命令针对不同的操作系统可能会出现不同的情况
	windows
    	如果直接下载成功了 那么忽略下面的操作
        如果下载失败需要你额外完成很多步操作
        参考文档:https://www.cnblogs.com/Dominic-Ji/p/9550525.html
        1.pip3 install wheel
        2.http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
            下载对应的文件
        3.pip3 install 文件名
        	获取下载的文件的存放路径,将文件拷贝至该路径下
        4.pip3 install pywin32
        5.pip3 install scrapy
        # 如何验证是否下载成功
       	在命令行里面输入scrapy如果有相应的返回结果表示下载成功了
        (环境变量一定要提前配置好python)
        
    mac
    	可以直接下载成功
    
"""
在使用pip3下载模块的时候可能会出现的报错
	1.报错信息里面含有readtimeout等关键字	
		原因是你当前网速不稳定,重新下载几次或者换宽带
	2.报错信息里面最后提示pip version关键字
		原因是你当前的pip版本过低,更新版本即可
		更新的语句在报错的提示里面直接就有
	3.报错信息里面一堆你根本看不懂的信息
		原因是该模块可能需要一定的系统环境
		或者模块版本有问题,或者系统兼容性问题
		出现这一类情况直接将报错信息拷贝到百度中搜索即可
"""

基本使用

robots.txt
	协议
 
# scrapy框架使用
		-新建项目
			-scrapy startproject 项目名字
		-新建爬虫
			-scrapy genspider 爬虫名 爬取的域名
		-项目目录介绍
			-spiders
				-所有的爬虫程序
			-items.py
				-类似于django的model类
			-middlewares.py
				-中间件
			-pipelines.py
				-持久化相关(数据存储)
			-settings.py
				-配置文件(关注:爬虫协议)
			-scrapy.cfg
				-部署相关
		-运行爬虫
			-scrapy crawl cnblogs --nolog
			
		-爬取数据
		
		//*[@id="post_list"]/div[1]
posted @ 2021-03-31 21:05  孔夫子挂妖刀  阅读(156)  评论(0)    收藏  举报