Python爬虫从编码到部署(这么一篇就够了!!!)
文章目录
一、导论
-
什么是爬虫?
答: 爬虫就是我们利用技术去模仿浏览器进行爬取数据的过程 -
爬虫在使用场景中的分类
-
通用爬虫
抓取系统重要组成部分。抓取的是一整张页面数据
-
聚焦爬虫
是建立在通用爬虫的基础之上。抓取的是页面中特定的局部内容
-
增量式爬虫
检测网站中数据更新的情况。只会抓取网站中最新更新出来的数据
-
-
robots.txt协议
只要在我要抓取数据的网站后添加
/robots.txt
就可以看到,人家允许哪些。不让哪些。
二、http协议
-
概念:
就是服务器和客户端进行数据交互的一种形式 -
常用请求头信息:
-User-Agent: 请求载体的身份标识
-Content-Type: 请求完毕后,是否断开连接还是保持连接
-
常用的响应头信息:
Content-Type:服务器端相应回客户端的数据类型 -
https协议
安全的超文本传输协议
-
加密方式
-
对称密钥加密
-
非对称密钥加密
-
证书密钥加密
-
三、request模块
request模块是python中原生的一款基于网络请求的模块,功能非常的强大,简单便捷,效率极高。、
-
作用:模拟浏览器发送请求
-
如何使用?
- 指定url
- 发起请求
- 获取响应数据
- 持久化存储
-
实战代码
#1.创建一个虚拟环境 conda create --name snowflake python #在pycharm中使用这个环境 #安装requests包 conda install requests
四、数据解析
聚焦爬虫
-
编码流程
- 指定url
- 发起请求
- 获取响应数据
- 数据解析
- 持久化存储
-
数据解析分类:
- 正则
- bs4
- xpath
-
数据解析原理概述
数据解析的局部的文本内容都会在标签之间或者标签对应的属性中进行存储。
1.进行指定标签的定位
2.标签或者标签对应的属性中存储的数据值进行提取(解析)
一、bs4进行数据解析
-
数据解析的原理
- 标签定位
- 提取标签、标签属性中存储的数据值
-
bs4数据解析的原理
1.实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
2.通过调用BeautifulSoup对象中的相关的属性或者方法进行标签定位和数据提取
-
环境安装
安装
bs4
和lxml
-
如何实例化BeautifalSoup对象
-
from bs4 import BeautifulSoup
-
对象的实例化:
-
将本地的html文档中的数据加载到该对象中
fp=open(’./test.html’,‘r’,encoding=‘utf-8’)
soup=BeautifulSoup(fp,‘lxml’)
-
将互连网上的获取的页面源码加载到该对象中
page_text=response.text
soup=BeautifulSoup(page_text,‘lxml’)
-
-
提供的用于数据解析的方法和属性:
-
soup.tagName:返回的是文档中第一次出现的tagName对应的标签
-
soup.find():
-
find(‘tagName’):等同于soup.div
-
属性定位:
soup.find(‘div’,class_/id/attr=‘song’)
-
soup.find_all(‘tagName’):返回的是符合要求的所有标签(列表)
-
-
select:
-select(‘某种选择器(id,class,标签,…选择器)’),返回的是一个列表
-层级选择器:
- soup.select(’.tang>ul>li>a’): 其中>表示的是一个层级
- soup.select(’.tang>ul a’): 空格表示的是多个层级
-
获取标签之间的文本数据:
-soup.a.text/string/get_text()
-text/get_text():可以获取一个标签中的所有的文本内容
-string: 只可以获取该标签下的直系的文本内容
-
获取标签中的属性值:
-soup.a[‘href’]
-
-
二、xpath解析
-
解析原理:
- 实例化一个etree的对象,同时且需要将被解析的页面源码数据加载到该对象中
- 调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获
-
实例化对象: from lxml import etree
-
将本地的html文档中的源码数据加载到etree对象中:
etree.parse(filePath) -
可以将从互联网上获取的源码数据加载到该对象中
etree.HTML('page_text')
-
-
xpath表达式
-
/:表示从根节点进行定位,表示的是一个层级
-
//:表示的是多个层级。可以表示从任意位置开始定位
-
属性定位://div[@class=‘song’] tag[@attrName=“attrValue”]
-
索引定位://div[@class=“song”]/p[3] 索引是从1开始的
-
取文本:
- /text() 取得是标签中的直系的文本内容
- // text() 取得是非直系的文本内容(所有的文本内容)
-
取属性:
/@attrName b 比如 ==》img/src
-
注意xpath不能包括
tbody
-
五、反爬与反反爬
一、反爬机质:
- 将验证码图片进行本地的下载
- 调用平台提供的示例代码进行图片数据的识别
六、模拟登录
一、爬取某些用户的用户信息
-
对人人网进行模拟登录
点击登录按钮后会发起一个post请求
post请求中会携带之前录入的相关登录信息(用户名、密码、验证码 。。。)
其中验证码每次请求都会变化
-
爬取当前用户相关的用户信息(个人主页中显示的用户信息)
-
https的协议特性是 无状态。
找不到对应页面数据的原因是:
发起的第二次基于个人主页的请求的时候,服务器端并不知道此请求是基于登录状态下的请求。
cookie:用来让服务器端记录客户端的相关状态
手动处理:通过抓包工具获取cookie值,将该值封装到headers中。(不建议)
自动处理:
-cookie值的来源是哪里?
--模拟登录post请求后,由服务器端进行创建
对此,我们的做法是:
- 创建一个session对象,session=request.Session()
- 使用session对象进行模拟登录post请求的发送,(cookie会被存储在session中)
- session对象对个人主页对应的get请求进行发送(携带了cookie)
七、scrapy框架的使用
1. 环境的安装
我发现要将python的版本进行下降,要不不好用
conda install python=3.6
conda install scrapy
2. scrapy的使用
- 基础代码
#创建一个工程:
scrapy startproject xxxPro
#进入工程
cd xxxPro
#创建爬虫文件
scrapy genspider spiderName www.xxx.com
#执行工程:
scrapy crawl spiderName
#如下指令可以实现将item提交的文件的输出
scrapy crawl spiderName -o myname.sve
-
配置文件的设置
ROBOTSTEX_OBEY=False LOG_LEVEL='ERROR'
3.持久化存储
-
基于终端指令:
- 要求:只可以将parse方法的返回值存储到本地的文本文件中
- 注意:持久化存储对应的文本文件的类型只可以为: json,jsonlines,jl,csv,xml
- 指令;
scrapy crawl xxx -o filePath
- 好处:简洁、高效、便捷
- 缺点:局限性比较强(数据只可以存储到指定后缀的文本文件中)
-
基于管道:
-
编码流程:
- 数据解析
- 在item类中定义相关的属性
- 将解析的数据封装存储到item类型的对象
- 将item类型的对象提交给管道进行持久化存储的操作
- 将管道类的process_item中要将接收到item对象中存储的数据进行持久化存储操作
- 在配置文件中开启管道
-
好处
-
-
通用性强、
-
注:管道文件中一个管道类对应的是将数据存储到一种平台
爬虫文件提交的item只会给管道文件中的第一个被执行的管道类接受
process_item中的return item表示将item传递给下一个即将被执行的管道类
4. 基于Spider的全站数据爬取
-
就是将网站中某板块下的全部页码对应的页面数据进行爬取
-
需求:爬取笑话网中的照片的名称
-
实现方式:
-
将所有页面的url添加到start_urls列表(不推荐)
-
自行手动进行请求发送(推荐)
-
手动请求发送:
yield scrapy.Request(url,callback)
:callback专门用于做数据解析
-
-
5. 五大核心组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ucwdCdA7-1629273435493)(E:\大三上学期\markdown编辑图片文件家\image-20210110183732196.png)]
这个图超级生动!!!
- 引擎(Scrapy): 用来处理整个系统的数据流处理,触发事务(框架核心)
- 调度器:用来接收引擎发过来的请求,压入队列中,并在引擎再次请求的时候返回,可以想象成一个URL(抓取网页的网址或者说是链接)的优先队列,由它来决定下一个要抓取的网址是什么,同时要去除重复的网址
- 下载器:用于下载网页内容,并将网页内容返回给蜘蛛。下载器是建立在twisted这个高效的异步模型上的
- 爬虫:爬虫主要是干活的,用于从特定的网页中爬取自己需要的信息,即所谓的实体,用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
- 项目管道: 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体,验证实体的有效性,清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
6. 请求传参
通过在meta属性进行传递
7.ImagesPipeline:
-
值越小,则其越先执行
-
只需要将img的src属性进行解析,提交到管道,管道就会对图片的src进行请求发送获取图片的二进制数据
-
需求:爬取站长素材中的高清图片
-
使用流程:
-
数据解析(图片的地址)
-
将存储图片地址的item提交到指定的管道类
-
在管道文件张自定制一个基于ImagePipeLine的一个管道类
- get_media_request
- file_path
- item_completed
-
在配置文件中:
- 指定图片存储的目录 :IMAGES_STORE=’./imgs_bobo’
- 指定开启的管道: 自定制的管道类
-
8. 中间件
-
下载中间件
-
位置: 引擎和下载器之间
-
作用:批量拦截到整个工程中所有的请求和相应‘
-
拦截请求
- UA伪装: process_request
- 代理IP: process_exception:return request
-
拦截相应:
- 篡改相应数据,相应对象
-
9. CrawSpider类,Spider的一个子类
-
全站数据爬取的方式
- 基于Spider:手动请求
- 基于CrawlSpider
-
CrawSpider的使用
-
创建一个工程
-
cd xxx
-
创建爬虫文件(CrawSpider):
#创建爬虫 scrapy genspider -t crawl xxx www.xxxx.com
-
链接提取器
-
-
作用: 根据指定的规则进行指定链接的提取
- 规则解析器
- 作用:将链接提取器提取到链接进行指定规则(callback)的解析
- follow=True 可以将链接提取器 继续作用到 链接提取器提取到的链接 所对应的页面中
- 规则解析器
10. 如何实现分布式?
1.简介
由多个服务器(操作系统-PC)组成,在调度器调度的情况下完成不同的任务,这种架构称为分布式。常见的调度器是消息中间件、服务注册中心、负载均衡等组成
-
安装一个scrapy-redis的组件
-
原生的scrapypy是不可以实现分布式爬虫,必须让scrapy结合着scrapy-redis组件一起实现分布式爬虫
-
为什么原生的scrapy不可以实现分布式
- 调度器不可以被分布式机群共享
- 管道不可以被分布式机群共享
-
scrapy-redis组件使用
-
可以给原生的scrapy框架提供可以被共享的管道和调度器
-
实现流程
-
创建一个工程
-
创建一个基于CrawSpider的爬虫文件
-
修改当前的爬虫文件
- 导包
from scrapy_redis.spiders import RedisCrawlSpider
- 将start_urls和allow_domains进行注释
- 添加一个新的属性:
redis_key='sun'
可以被共享的调度器队列的名称 - 编写数据解析相关的操作
- 将当前的爬虫类的父类修改为 RedisCrawlSpider
- 导包
-
修改配置文件 settings
#指定使用可以被共享的管道 ITEM_PIPELINES={ 'scrapy_redis.pipelines.RedisPipeline':400 } #指定调度器 #添加了一个去重容器类的配置,作用使用Redis的set集合来存储请求的指纹数据 DUPEFILTER_CLASS="scrapy_redis.dupefilter.RFPDupeFilter" #使用scrapy-redis组件的调度器 SCHEDULER="scrapy_redis.scheduler.Scheduler" #配置调度器是否要持久化,也就是当爬虫结束了,要不要清空Redis中请求队列 SCHEDULER_PERSIST=True #地址reedis REDIS_HOST='127.0.0.1' REDIS_PORT=6379
-
redis相关操作配置
-
配置redis的配置文件
- linux或者mac: redis.conf
- windows:redis.windows.conf
- 代开配置文件修改
- 将 bind 127.0.0.1 进行删除
- 关闭保护模式: protected-mode yes 改为no
- 结合着配置文件中开启redis服务
-
-
-
redis-server 配置文件
+ 启动客户端 + `redis-cli` + 执行工程: `scrapy runspider xxx.py` + 向调度器的队列中加入一个起始的url: + 调度器的队列在redis的客户端中(在本地的cmd中) `lpush xxx www.xxx.com` + 爬取到的数据存储在了redis的proName: items这个数据结构中
八、增量式爬虫
-
概念:检测网站数据更新的情况,只会爬取网站最新更新出来的数据
-
分析:
-
指定一个起始url
-
基于CrawlSpider获取其它页码链接
-
基于Rule将其它页面链接进行请求
-
从每一个页码对应的页面源码中解析出每一个电影详情页的URL
-
核心: 检测电影详情页的url之前有没有请求过
- 将爬取过的电影详情页的url存储
- 存储到redis的set数据结构
-
对详情页的url发起请求,然后解析出电影的名称和简介
-
进行持久化存储
-
九、爬虫的部署
1.原生的部署方法
1.下载google内核
# 去这个地址,下载对应的windows或者 linux的内核,
#http://chromedriver.storage.googleapis.com/index.html
#如果要看linux的goole的版本,请输入 google-chrome --version
http://chromedriver.storage.googleapis.com/index.html
2.本地文件的准备
-
代码部分
#1 设置我们的浏览器为无头方式、并且进行一些必要的参数的设置 chrome_options = Options() chrome_options.add_argument('--headless') chrome_options.add_argument('--no-sandbox') chrome_options.add_argument('--disable-gpu') chrome_options.add_argument('--disable-dev-shm-usage') #2 设置浏览器的内核位置,这里的地址要注意写上我们的浏览器地址为绝对的地址才好用呢 bro=webdriver.Chrome(executable_path='/study/spirderProject/heuPro/chromedriver',chrome_options=chrome_options,options=option)
-
同步包的管理
cd 项目目录 pip install pipreqs pipreqs ./ #执行上述的内容之后,就会产生一个requiments.txt文件,该文件相当于包的锁 #另外一种方法是 pip3 freeze >requirements.txt,但是对于不同的机器之间不要使用这个方法,因为这个会记录所有的包,并且不兼容,也不好用
-
配置部分
- 先在pycharm->Tools->Deployment->Configuration
- 点击 + 号,选择SFTP,在弹出框中填写如我们的配置的文件的名称
- 点击配置SSH configuration,同时填写Host,User name, Authentication type ,Password等,填写完毕后我们进行测试,成功以后点击确定
- 在Mappings中,我们设置Deployment path ,这个目录是远程服务器的文件上传的地址
- 当我们需要进行文件的上传部署的时候,只需要在项目目录上右键–>Deployment–Upload to xxxxxx,点击之后,文件就上传啦
3 服务器的配置
-
设置启动谷歌浏览器的时候,不用x-manage窗口
- 右键 x-shell的连接中的某个链接–>属性
- ssH–>隧道–>x11的转移进行取消 ,点击确定
-
创建python虚拟环境,并且根据包管理锁安装包
conda create --name spider biopython source activate spider cd 项目目录 pip install -r requirements.txt
-
安装谷歌浏览器,并且下载内核,放到相应的位置(和python中的代码相匹配)
#内核如何下载在前面 # 安装64位 linux的谷歌浏览器 wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb # 进行安装 sudo dpkg -i google-chrome* #如果报错,就执行下面的语句,然后继续执行 sudo apt-get -f install
-
给内核执行的权限
chmod -R 777 chromedriver.exe
4.进行执行
scrapy crawl getCj
2. 通过scrapyd方法部署
据我所知,scrapyd和scrapyd-client是scrapy官方给我们写好的框架,希望我们通过这个来进行部署
-
这个我遇到了一个问题,就是一旦使用 __ init __ ()将其重写,并且用selenium的时候,一定要注意加上参数,而不是(self)这一个单纯的参数
def __init__(self, *args, **kwargs): # 实现无可视化界面的操作 ... ...
1.服务器端操作
#1安装
pip install scrapyd
pip install scrapyd-client
#2配置scrapyd的可访问ip和端口号
cd /root/anaconda3/envs/spider/lib/python3.6/site-packages/scrapyd
vim app.py
# 如下进行配置,分别为端口号和主机地址
app = Application("Scrapyd")
http_port = config.getint('http_port', 6800)
bind_address ='0.0.0.0' # config.get('bind_address', '127.0.0.1')
poll_interval = config.getfloat('poll_interval', 5)
#3启动
scrapyd
#4可以进行访问,其中job是上传过的爬虫项目,log是运行日志窗口,Documentation 是文件资料
#推荐后台运行
cd 到项目目录
nohup scrapyd &
接下来要做的就是通过nginx反向代理scrapyd端口,同时进行这个本地操作
2 本地操作
#1 配置本地项目的scrapy.cfg文件
[deploy:版本号]
url=服务器的访问公网地址:端口/
project= 项目名称
#2 将项目推送到远程服务器,并且将某个项目加入scrapyd的管理之中
右键,将项目推送上去
#如下语句,在服务器中进行执行
scrapyd-deploy 版本号 -p 项目名称
#3本地进行远程的爬虫控制
点击python console
import requests
data={}
data['project']='heuPro'
#值得注意的是这里的spider的名字一定要和原来项目中的爬虫文件的名字对应起来,要不就不会好用
data['spider']='getCj'
url='http://192.144.239.108:6800/schedule.json'
resp=requests.post(url,data)
#进行结果的显示
resp.json()
#4 结束并且删除项目
url='http://192.144.239.108:6800/schedule.json'
data['project']='heuPro'
resp=requests.post(url,data)
3. scrapyd相关指令
#1获取当前的执行状态
http://127.0.0.1:6800/daemonstatus.json
#2 获取项目列表
http://127.0.0.1:6800/listprojects.json
#3获取项目已经发布的爬虫列表
http://127.0.0.1:6800/listspiders.json?project=myproject
#4获取项目下已经发布的爬虫版本列表
http://127.0.0.1:6800/listversions.json?project=myproject
#5获取爬虫运行状态
http://127.0.0.1:6800/listjobs.json?project=myproject
#6启动服务器上的某一个爬虫(必须是已经发布到服务器的爬虫)
http://127.0.0.0.1:6800/schedule.json
(post方式,data={"project":myproject,"spider":myspider})
返回数据 jobid
注意,如果爬虫程序需要创建文件目录,这个目录必须指定相对
#7停止爬虫
curl http://localhost:6800/cancel.json -d project=项目名称 -d job=工作编号
#8删除某一版本的爬虫
http://127.0.0.1:6800/delversion.json
(post方式,data={"project":myproject,"version":myversion})
#9 删除某个爬虫工程
http://127.0.0.1:6800/delproject.json(post方式,data={"project":myproject})
3.docker部署
1.安装并且配置ubuntu容器
#1安装ubuntu容器
docker pull ubuntu
#2启动并且进入容器
docker run -dit --name server ubuntu
docker exec -it server bash
#3进行一系列基本配置
apt-get update
apt-get upgrade
apt-get install vim
apt-get install wget
cd /home
mkdir download
cd download
# 然后就是板板正正的安装谷歌浏览器
# 通过之前的重装系统那更新apt-get的源
#4 安装一系列的安装包,我们使用pip就是python2.7,pip3就是python3.7
apt install python3-pip
apt install python-pip
pip3 install scrapyd
apt install cron
#5 将容器退出,
exit
docker stop server
#6. 将我们设置之后的容器进行镜像的打包到本地
#docker commit -m '消息' -a '作者' 容器名 打包的镜像名
docker commit -m 'Python3 for Ubuntu18.04' -a 'Yang Peihao' server ubuntu/python3
2.在本地的文件编写
2.1编写Dockerfile文件
# 先找服务器本地的images,如果没有就去仓库拉取下载
FROM ubuntu/python3
#以下的环境语言一定要进行设置
ENV LANG C.UTF-8
# 作者和作者的连续方式
MAINTAINER YangPeihao 15166675416@163.com
#将当下的文件添加到启动后容器的/usr/src目录下
ADD . /usr/src
# 设置文件的同步,对应启动容器的-v 参数
VOLUME /usr/src
# 定位到容器中 /usr/src目录地址下
WORKDIR /usr/src
# 将要执行的服务器指令
RUN pip3 install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
# 给脚本文件可执行的权限
RUN chmod +x run.sh
# 当镜像制作完成后,就执行这个脚本文件
CMD /usr/src/run.sh
2.2 编写run.sh
#!/bin/bash
cd /usr/src
scrapy crawl getCj
要注意的如下,一定要设置编码方式为LF
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eoPug7RF-1629273435496)(E:\大三上学期\markdown编辑图片文件家\image-20210119201447747.png)]
3.在远程服务器中运行项目
cd 文件项目目录
docker build -t getcj:1.0 .
#先在裸机上给脚本执行的权限,否则加入容器后也不好用
chmod +x run.sh
docker run -dit --name spider_getcj -v /study/spidersPro/heuPro/:/usr/src getcj:1.0
docker logs spider_getcj -f
4.定时爬虫crontab
1.制作一个要自动执行的批处理文件
- vim runspider.sh
#!/bin/bash
docker start spider_getcj
# 制作完成后,给该脚本执行权限
chmod +x runspider.sh
#添加软连接
ln -s /study/spirderProject/heuPro/runspider.sh /usr/bin/get_cj
# 我们可以在这个基础上进行测试,直接输入指令,正常来说就可以执行
#get_cj
2.添加定时任务
#1 编辑定时任务
cd /study/myCronTab-Plans
#2 编辑文件,vim getcj.cron
*\5 * * * * get_cj
#3 将该定时任务添加
crontab getcj.cron
crontab -l
十 bug的解决
1. windows系统中提示 Message: ‘chromedriver’ executable needs to be in PATH
# 将内核放在python文件的根文件中,因为我是用到anaconda,所以把内核放在D:\ProgramData\Anaconda3
#代码这样用self.bro = webdriver.Chrome(executable_path='chromedriver92.exe', chrome_options=chrome_options,
# options=option)
2.Linux系统中提示Message: ‘chromedriver’ executable needs to be in PATH
#1.修改环境变量
cd /etc
sudo vim profile
#2. 在末尾增加
export PATH=$PATH:/study/spidersPro/PingAnDaKaPro/PingAnDaKaPro/chromedriver
#3. 激活环境
source profile
#4.查看当前环境变量
echo $PATH
#然后在源码中使用内核代码如下:
self.bro = webdriver.Chrome(executable_path='/study/spidersPro/PingAnDaKaPro/PingAnDaKaPro/chromedriver', chrome_options=chrome_options,options=option)