Ⅰ 案例登陆京东(滑块验证)
【一】下载opencv库
pip install opencv-python
【二】数据准备
- 先将京东的滑块图片下载到本地
- 背景图background.png
- 滑块图tag.png
【三】展示获取滑块的移动数据
import os.path
# 使用 opencv 识别图像计算滑块之间的距离
import cv2
import numpy as np
class CvImageDistance:
def from_file_get_distanct(self, tag_img_path, background_img_path):
'''
根据文件进行识别
:param tag_img_path: 滑块图片的文件路径
:param background_img_path: 背景图片的文件路径
:return:
'''
# 滑块
target = cv2.imread(tag_img_path)
# 读取到两个图片,进行灰值化处理
# 背景缺口图
template = cv2.imread(background_img_path, 0)
# 转化到灰度
target = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
# 返回绝对值
target = abs(255 - target)
# 单通道转3通道
target = cv2.cvtColor(target, cv2.COLOR_GRAY2RGB)
template = cv2.cvtColor(template, cv2.COLOR_GRAY2RGB)
# 进行匹配
result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)
# 通过np转化为数值,就是坐标
x, y = np.unravel_index(result.argmax(), result.shape)
return y, x
def from_buffer_get_distanct(self, tag_img, background_img):
'''
根据二进制进行识别
:param tag_img_path: 滑块图片的二进制
:param bg: 背景图片的二进制
:return:
'''
target = cv2.imdecode(np.frombuffer(tag_img, np.uint8), cv2.IMREAD_COLOR)
# 如果是PIL.images就换读取方式
template = cv2.imdecode(np.frombuffer(background_img, np.uint8), cv2.IMREAD_COLOR) if type(
background_img) == bytes else cv2.cvtColor(
np.asarray(background_img), cv2.COLOR_RGB2BGR)
# 转化到灰度
target = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
# 返回绝对值
target = abs(255 - target)
# 单通道转3通道
target = cv2.cvtColor(target, cv2.COLOR_GRAY2RGB)
# 进行匹配
result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)
# 通过np转化为数值,就是坐标
x, y = np.unravel_index(result.argmax(), result.shape)
return y, x
def get_distance(self, background_img_path, tag_img_path):
# 读取到背景图片的 rgb
background_rgb = cv2.imread(background_img_path)
# 读取到滑块图片的 rgb
tag_rgb = cv2.imread(tag_img_path)
# 计算结果
res = cv2.matchTemplate(background_rgb, tag_rgb, cv2.TM_CCOEFF_NORMED)
# 获取最小长度
lo = cv2.minMaxLoc(res)
# 识别返回滑动距离
return lo[2][0]
if __name__ == '__main__':
tag_img_path = os.path.join(os.path.dirname(__file__), 'tag.png')
background_img_path = os.path.join(os.path.dirname(__file__), 'background.png')
with open(tag_img_path, 'rb') as f:
tag_img = f.read()
with open(background_img_path, 'rb') as f:
background_img = f.read()
cv_obj = CvImageDistance()
print(cv_obj.from_buffer_get_distanct(tag_img, background_img)) # (np.int64(136), np.int64(24))
print(cv_obj.get_distance(background_img_path, tag_img_path)) # 136
- background.png
- tag.png
【四】代码实现
import random
import time
import cv2
from urllib import request
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from cvImg import CvImageDistance
from selenium.webdriver.chrome.service import Service
class SpiderJd:
def __init__(self, username, password):
self.username = username
self.password = password
self.index_url = 'https://www.jd.com'
self.cv_obj = CvImageDistance()
self.browser = webdriver.Chrome(
service=Service(executable_path="./chromedriver.exe")
)
def __sleep_time(self):
time.sleep(random.randint(1, 3))
def login(self):
# 【一】访问京东官网
self.browser.get(self.index_url)
self.__sleep_time()
# 【二】在页面上找到请登陆的按钮
login_btn = self.browser.find_element(By.XPATH, '//*[@id="ttbar-login"]/a[1]')
# 【三】点击登陆按钮跳转到登陆界面
login_btn.click()
self.__sleep_time()
# 【四】获取到用户名和密码的输入框
username_input = self.browser.find_element(By.XPATH, '//*[@id="loginname"]')
password_input = self.browser.find_element(By.XPATH, '//*[@id="nloginpwd"]')
# 输入用户名和密码
username_input.send_keys(self.username)
self.__sleep_time()
password_input.send_keys(self.password)
self.__sleep_time()
# 【五】获取登陆按钮
login_submit = self.browser.find_element(By.XPATH, '//*[@id="loginsubmit"]')
# 【六】点击登陆按钮
login_submit.click()
self.__sleep_time()
# 【七】弹出滑动验证码
# (1)获取到当前验证码所在的标签
# 需要移动的滑块的标签
code_img_tag = self.browser.find_element(By.XPATH,
'//*[@id="JDJRV-wrap-loginsubmit"]/div/div/div/div[1]/div[2]/div[2]/img')
# 滑块背景图完整的图片
code_img_background_tag = self.browser.find_element(By.XPATH,
'//*[@id="JDJRV-wrap-loginsubmit"]/div/div/div/div[1]/div[2]/div[1]/img')
code_btn_tag = self.browser.find_element(By.XPATH,
'//*[@id="JDJRV-wrap-loginsubmit"]/div/div/div/div[2]/div[3]')
# (2)获取得到滑块背景图的完整图片和滑块图片
background_img = code_img_background_tag.get_attribute("src")
tag_img = code_img_tag.get_attribute("src")
# (3)解析当前图片链接得到本地的图片
request.urlretrieve(background_img, "background.png")
request.urlretrieve(tag_img, "tag.png")
self.__sleep_time()
# (4)计算缺口之间的距离
distance = self.cv_obj.get_distance(background_img_path="background.png", tag_img_path="tag.png")
x_location = int(distance * 240 / 360)
# 【八】准备滑块滑动
# (1)创建滑块动作链对象
action = ActionChains(self.browser)
# (2)按住滑块
action.click_and_hold(code_btn_tag)
# (3)滑动到指定位置
# 定义起始位置
track = 0
while track < x_location:
# 每次只划一部分
action.move_by_offset(2, 0).perform()
# 累加
track += 2
self.__sleep_time()
# (4)释放滑块
action.release(code_btn_tag).perform()
self.__sleep_time()
if __name__ == '__main__':
spider = SpiderJd(
username="15036883333",
password="666666zczczczcz"
)
spider.login()
- cvImg.py
import os.path
import cv2
import numpy as np
class CvImageDistance:
def from_file_get_distanct(self, tag_img_path, background_img_path):
'''
根据文件进行识别
:param tag_img_path: 滑块图片的文件路径
:param background_img_path: 背景图片的文件路径
:return:
'''
target = cv2.imread(tag_img_path)
# 读取到两个图片,进行灰值化处理
template = cv2.imread(background_img_path, 0)
# 转化到灰度
target = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
# 返回绝对值
target = abs(255 - target)
# 单通道转3通道
target = cv2.cvtColor(target, cv2.COLOR_GRAY2RGB)
template = cv2.cvtColor(template, cv2.COLOR_GRAY2RGB)
# 进行匹配
result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)
# 通过np转化为数值,就是坐标
x, y = np.unravel_index(result.argmax(), result.shape)
return y, x
def from_buffer_get_distanct(self, tag_img, background_img):
'''
根据二进制进行识别
:param tag_img_path: 滑块图片的二进制
:param bg: 背景图片的二进制
:return:
'''
target = cv2.imdecode(np.frombuffer(tag_img, np.uint8), cv2.IMREAD_COLOR)
# 如果是PIL.images就换读取方式
template = cv2.imdecode(np.frombuffer(background_img, np.uint8), cv2.IMREAD_COLOR) if type(
background_img) == bytes else cv2.cvtColor(
np.asarray(background_img), cv2.COLOR_RGB2BGR)
# 转化到灰度
target = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
# 返回绝对值
target = abs(255 - target)
# 单通道转3通道
target = cv2.cvtColor(target, cv2.COLOR_GRAY2RGB)
# 进行匹配
result = cv2.matchTemplate(target, template, cv2.TM_CCOEFF_NORMED)
# 通过np转化为数值,就是坐标
x, y = np.unravel_index(result.argmax(), result.shape)
return y, x
def get_distance(self, background_img_path, tag_img_path):
# 读取到背景图片的 rgb
background_rgb = cv2.imread(background_img_path)
# 读取到滑块图片的 rgb
tag_rgb = cv2.imread(tag_img_path)
# 计算结果
res = cv2.matchTemplate(background_rgb, tag_rgb, cv2.TM_CCOEFF_NORMED)
# 获取最小长度
lo = cv2.minMaxLoc(res)
# 识别返回滑动距离
return lo[2][0]
if __name__ == '__main__':
tag_img_path = os.path.join(os.path.dirname(__file__), 'tag.png')
background_img_path = os.path.join(os.path.dirname(__file__), 'background.png')
with open(tag_img_path, 'rb') as f:
tag_img = f.read()
with open(background_img_path, 'rb') as f:
background_img = f.read()
cv_obj = CvImageDistance()
print(cv_obj.from_buffer_get_distanct(tag_img, background_img))
print(cv_obj.get_distance(background_img_path, tag_img_path))
Ⅱ 验证码识别
【一】图鉴平台
【1】官网
【2】介绍
- 比较好用的平台
【3】价格
【4】使用
- http://www.ttshitu.com/docs/python.html#pageTitle
- 查看开发文档按照开发文档使用即可
import base64
import json
import requests
# 一、图片文字类型(默认 3 数英混合):
# 1 : 纯数字
# 1001:纯数字2
# 2 : 纯英文
# 1002:纯英文2
# 3 : 数英混合
# 1003:数英混合2
# 4 : 闪动GIF
# 7 : 无感学习(独家)
# 11 : 计算题
# 1005: 快速计算题
# 16 : 汉字
# 32 : 通用文字识别(证件、单据)
# 66: 问答题
# 49 :recaptcha图片识别
# 二、图片旋转角度类型:
# 29 : 旋转类型
#
# 三、图片坐标点选类型:
# 19 : 1个坐标
# 20 : 3个坐标
# 21 : 3 ~ 5个坐标
# 22 : 5 ~ 8个坐标
# 27 : 1 ~ 4个坐标
# 48 : 轨迹类型
#
# 四、缺口识别
# 18 : 缺口识别(需要2张图 一张目标图一张缺口图)
# 33 : 单缺口识别(返回X轴坐标 只需要1张图)
# 五、拼图识别
# 53:拼图识别
def base64_api(uname, pwd, img, typeid):
with open(img, 'rb') as f:
base64_data = base64.b64encode(f.read())
b64 = base64_data.decode()
data = {"username": uname, "password": pwd, "typeid": typeid, "image": b64}
result = json.loads(requests.post("http://api.ttshitu.com/predict", json=data).text)
if result['success']:
return result["data"]["result"]
else:
#!!!!!!!注意:返回 人工不足等 错误情况 请加逻辑处理防止脚本卡死 继续重新 识别
return result["message"]
return ""
if __name__ == "__main__":
img_path = "C:/Users/Administrator/Desktop/file.jpg"
result = base64_api(uname='你的账号', pwd='你的密码', img=img_path, typeid=3)
print(result)
【二】超级鹰
【1】官网
【2】介绍
【3】价格
【4】使用
import requests
from hashlib import md5
class Chaojiying_Client(object):
def __init__(self, username, password, soft_id):
self.username = username
password = password.encode('utf8')
self.password = md5(password).hexdigest()
self.soft_id = soft_id
self.base_params = {
'user': self.username,
'pass2': self.password,
'softid': self.soft_id,
}
self.headers = {
'Connection': 'Keep-Alive',
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
}
def PostPic(self, im, codetype):
"""
im: 图片字节
codetype: 题目类型 参考 http://www.chaojiying.com/price.html
"""
params = {
'codetype': codetype,
}
params.update(self.base_params)
files = {'userfile': ('ccc.jpg', im)}
r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files,
headers=self.headers)
return r.json()
def PostPic_base64(self, base64_str, codetype):
"""
im: 图片字节
codetype: 题目类型 参考 http://www.chaojiying.com/price.html
"""
params = {
'codetype': codetype,
'file_base64': base64_str
}
params.update(self.base_params)
r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, headers=self.headers)
return r.json()
def ReportError(self, im_id):
"""
im_id:报错题目的图片ID
"""
params = {
'id': im_id,
}
params.update(self.base_params)
r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
return r.json()
if __name__ == '__main__':
chaojiying = Chaojiying_Client('超级鹰用户名', '超级鹰用户名的密码', '96001') # 用户中心>>软件ID 生成一个替换 96001
im = open('a.jpg', 'rb').read() # 本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
print(chaojiying.PostPic(im, 1902)) # 1902 验证码类型 官方网站>>价格体系 3.4+版 print 后要加()
# print chaojiying.PostPic(base64_str, 1902) #此处为传入 base64代码
Ⅲ Scrapy框架介绍
【一】开源和协作的框架
-
其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,
-
使用它可以以快速、简单、可扩展的方式从网站中提取所需的数据。
-
但目前Scrapy的用途十分广泛,可用于如数据挖掘、监测和自动化测试等领域,也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。
-
Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。
-
因此Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。
-
Scrapy框架类似于Django框架
【二】整体架构大致如下
【1】引擎(EGINE)
- 引擎负责控制系统所有组件之间的数据流,并在某些动作发生时触发事件。
【2】调度器(SCHEDULER)
- 用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回.
- 可以想像成一个URL的优先级队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
【3】下载器(DOWLOADER)
- 用于下载网页内容, 并将网页内容返回给EGINE,下载器是建立在twisted这个高效的异步模型上的
【4】爬虫(SPIDERS)
- SPIDERS是开发人员自定义的类,用来解析responses,并且提取items,或者发送新的请求
【5】项目管道(ITEM PIPLINES)
- 在items被提取后负责处理它们,主要包括清理、验证、持久化(比如存到数据库)等操作
- 下载器中间件(Downloader Middlewares)位于Scrapy引擎和下载器之间,主要用来处理从EGINE传到DOWLOADER的请求request,已经从DOWNLOADER传到EGINE的响应response,
【6】爬虫中间件(Spider Middlewares)
- 位于EGINE和SPIDERS之间,主要工作是处理SPIDERS的输入(即responses)和输出(即requests)
【三】官网链接
Ⅳ Scrapy框架之安装
# window系统
pip install scrapy
# macos / linux
pip install scrapy
【一】Windows平台
【1】安装wheel文件
- 在 Windows 平台上安装 Scrapy 之前
- 首先需要安装 wheel 文件。wheel 文件是一种 Python 包的分发格式,可以方便地进行安装。
- 可以通过以下命令来安装 wheel:
pip3 install wheel
【2】安装 lxml 解析器
- Scrapy 使用 lxml 解析器来进行 HTML 和 XML 的解析工作。
- 要安装 lxml,可以执行以下命令:
pip3 install lxml
【3】安装 pyopenssl
- Scrapy 在进行 HTTPS 请求时,需要使用 pyopenssl 模块来提供 SSL/TLS 支持。
- 安装 pyopenssl 可以使用以下命令:
pip3 install pyopenssl
【4】下载并安装pywin32
- 下载并安装 pywin32 可以从其官网下载最适合您的版本:https://sourceforge.net/projects/pywin32/files/pywin32/
- 请根据您的操作系统和Python版本选择正确的安装文件进行下载。
- 下载完成后,按照安装向导进行安装。
【5】下载twisted的wheel文件
- 要安装 Scrapy,需要先下载 twisted 的 wheel 文件。
- 可以从官方网站下载 twisted 的 wheel 文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
- 请注意选择与您的Python环境相匹配的 wheel 文件进行下载。
【6】安装twisted
- 下载完成 twisted 的 wheel 文件后,可以使用以下命令安装 twisted:
pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd**.whl
- 将 下载目录 替换为你实际下载 twistedwheel 文件所在的目录
- 并根据您的 Python 环境选择正确的文件名进行替换。
【7】安装scrapy
- 可以优先尝试这个命令,报错再按照上述安装对应的依赖
- 当上述依赖项都安装完成后,可以使用以下命令来安装 Scrapy:
pip3 install scrapy
【二】Linux平台
- 在 Linux 平台上安装 Scrapy,可以通过以下命令进行安装:
pip3 install scrapy
Ⅴ Scrapy框架之基本使用
# 【一】创建爬虫项目
# startproject 项目名字
# 【二】创建爬虫文件
# cd 项目
# scrapy genspider 爬虫文件名 允许访问的域名
# 【三】启动爬虫
# 执行爬虫程序
# 【四】创建一个 Request 对象
# 将 start_urls 列表里面的网址包装成 Request 对象 向目标地址发起请求
# 【五】去调度器引擎 把 请求交给引擎 让引擎分配任务
# 【六】调度器引擎 把 请求 拿过来 下一步 在会给引擎
# 【七】引擎交给下载器 下载器下载数据
# 【八】将下载好的数据返回给引擎并生成一个 Response 对象
# 【九】爬虫程序逻辑中
# 对数据进行解析和下载
# 【十】下载完成后又回到引擎 再调度 地址生成request 对象
【一】查看帮助
scrapy -h
scrapy <command> -h
- 第一个命令用于查看全部可用命令的帮助信息
- 第二个命令用于查看特定命令的帮助信息
【二】全局命令和项目命令
- Project-only必须切到项目文件夹下才能执行
- Global的命令则不需要
Global commands:
startproject #创建项目
genspider #创建爬虫程序
settings #如果是在项目目录下,则得到的是该项目的配置
runspider #运行一个独立的python文件,不必创建项目
shell #scrapy shell url地址 在交互式调试,如选择器规则正确与否
fetch #独立于程单纯地爬取一个页面,可以拿到请求头
view #下载完毕后直接弹出浏览器,以此可以分辨出哪些数据是ajax请求
version #scrapy version 查看scrapy的版本,scrapy version -v查看scrapy依赖库的版本
Project-only commands:
crawl #运行爬虫,必须创建项目才行,确保配置文件中ROBOTSTXT_OBEY = False
check #检测项目中有无语法错误
list #列出项目中所包含的爬虫名
parse #scrapy parse url地址 --callback 回调函数 #以此可以验证我们的回调函数是否正确
bench #scrapy bentch压力测试
【1】全局命令(Global commands)
- startproject:创建一个新的 Scrapy 项目。
- genspider:创建一个新的爬虫程序。
- settings:显示一个 Scrapy 项目的配置信息。
- runspider:运行一个独立的 Python 文件作为爬虫,不需要创建项目。
- shell:进入 Scrapy 的交互式调试环境,可以检查选择器规则是否正确。
- fetch:单独请求一个页面,并获取响应结果。
- view:下载指定页面并在浏览器中打开,用于检查通过哪些请求获取数据。
- version:查看当前安装的 Scrapy 版本号。
【2】项目命令(Project-only commands)
- crawl:运行一个 Scrapy 爬虫,必须在项目目录下执行且确保配置文件中的 ROBOTSTXT_OBEY 设置为 False。
- check:检查项目中是否存在语法错误。
- list:列出项目中包含的所有爬虫名称。
- parse:使用回调函数解析给定的 URL,用于验证回调函数是否正确。
- bench:用于对 Scrapy 进行压力测试。
【3】官网链接
- 如果需要更详细的命令信息,可以参考 Scrapy 官方文档的命令行工具部分
- https://docs.scrapy.org/en/latest/topics/commands.html
【三】创建项目
【1】创建步骤
(1)创建项目命令
- 通过 Scrapy 命令创建项目
scrapy startproject 项目名
scrapy startproject SpiderNewsProjects
(2)进入爬虫项目文件
- 切换到爬虫项目目录
cd SpiderNewsProjects
(3)创建spider项目
- 创建自定义的爬虫程序脚本
scrapy genspider 自定爬虫程序文件名 目标网址
- 示例
scrapy genspider wangyi news.163.com
scrapy genspider huanqiu huanqiu.com
- 创建成功后会在 spiders文件夹下看到我们创建的自定义的文件名的py文件
【2】目录结构
(1)概览
├── NewsPro # 项目名
│ ├── __init__.py
│ ├── items.py # 类似于django的 models表模型,一个个模型类
│ ├── middlewares.py # 中间件
│ ├── pipelines.py # 管道---》写持久化
│ ├── settings.py # 项目配置文件
│ └── spiders # 里面放了自定义的爬虫,类似于app
│ ├── __init__.py
│ ├── huanqiu.py # 自定义爬虫文件
│ └── wangyi.py # 自定义爬虫文件
└── scrapy.cfg # 项目上线配置
(2)说明
- scrapy.cfg
- 项目的主配置信息,用来部署scrapy时使用,爬虫相关的配置信息在settings.py文件中。
- items.py
- 设置数据存储模板,用于结构化数据
- 如:Django的Model
- pipelines
- 数据处理行为
- 如:一般结构化的数据持久化
- settings.py
- 配置文件
- 如:递归的层数、并发数,延迟下载等。强调:配置文件的选项必须大写否则视为无效,正确写法USER_AGENT='xxxx'
- spiders
- 爬虫目录
- 如:创建文件,编写爬虫规则
【四】简单使用
- wangyi.py
import scrapy
# 自动以当前文件夹命名的类型
class WangyiSpider(scrapy.Spider):
# 爬虫文件的唯一标识
name = "wangyi"
# 允许访问的域名
allowed_domains = ["news.163.com"]
# 起始 的 URL 列表 (重要)
# 列表内部的 url 都会被框架进行异步请求发送
start_urls = ["http://news.163.com/"]
# 数据解析主函数:自动调用
# 调用的次数取决于 start_urls 列表内元素的个数
def parse(self, response):
# response : 表示的就是响应对象
print("response:::", response.text)
【五】启动项目
- 通过指定的命令启动 Scrapy 项目,而非通过文件启动
# 【1】纯命令行
scrapy crawl baidu
# 【2】py 文件启动
在项目根目录下创建一个启动py文件
from scrapy.cmdline import execute
execute(['scrapy', 'crawl', '自定义爬虫文件名', "--nolog"])
【六】优化启动
【1】降低日期等级
- 在 settings.py 文件中添加指定配置项
# 指定输出日志的类型:
LOG_LEVEL = 'ERROR'
【2】不遵循ROBOTS协议
ROBOTSTXT_OBEY = False
【3】以启动文件启动项目
- 每一次终端启动和麻烦,我们可以在项目根目录下新建启动文件
- bin.py:
from scrapy.cmdline import execute
execute(['scrapy', 'crawl', '自定义爬虫文件名', "--nolog"])
Ⅵ Scrapy框架之数据解析
【一】项目准备
【1】前言
- 如果终端还在第一个项目的文件夹中,则需要在终端中执行cd ../返回到上级目录,在去新建另一个项目。
【2】创建项目步骤
(1)创建工程
scrapy startproject 项目名称
(2)切换到项目目录
cd 项目名称
(3)创建爬虫文件
scrapy genspider 爬虫文件名 www.xxx.com
(4)配置文件的修改
- settings.py
# 不遵从robots协议
ROBOTSTXT_OBEY = False
# 指定输出日志的类型:
LOG_LEVEL = 'ERROR'
from fake_useragent import UserAgent
# 指定UA:
USER_AGENT = UserAgent().random
(5)编写爬虫文件:
- spiders/爬虫文件名.py
【3】启动项目
- 命令启动
scrapy crawl spider_news
- 项目根目录下新建启动文件
- start.py:
from scrapy.cmdline import execute
execute(['scrapy', 'crawl', '爬虫文件名', "--nolog"])
【4】项目执行流程简解
- 启动爬虫:
- 开始执行爬虫程序。
- 创建Request对象:
- 将start_urls地址包装成request对象,其中包含待爬取的网页链接、回调函数等信息。
- 交给引擎:
- 将创建好的request对象交给引擎进行处理。
- 调度器排队:
- 引擎将请求交给调度器,调度器按照一定的策略(如先进先出)将请求放入队列中进行排队。
- 引擎处理:
- 引擎从调度器中取出请求,并选择合适的下载中间件进行处理。
- 下载器处理:
- 下载器根据请求中的链接发起网络请求,下载相应的页面内容,并将下载结果返回给引擎。
- 下载完成:
- 下载器将网页内容下载完成后,将下载结果返回给引擎。
- 引擎传递给爬虫:
- 引擎将下载结果传递给相应的爬虫解析函数(例如parse函数)进行处理。
- 爬虫解析:
- 爬虫解析函数对下载下来的网页内容进行解析,提取出需要的数据,并生成新的Request对象或是Item对象。
- 回到步骤2:
- 解析函数可以继续生成新的Request对象,或是处理Item对象
- 然后回到步骤2,继续执行后续的请求和解析过程。
【二】爬虫文件结构解析
import scrapy
# 爬虫类,继承了scrapy.Spider
class FirstSpider(scrapy.Spider):
# 爬虫文件的名称,是当前爬虫文件的唯一标识
name = "first"
# 允许访问的域名
allowed_domains = ["www.cnblogs.com/"]
# 起始的url列表:可以将即将被请求的url,存放在当前列表中。
# 默认情况,列表中存储的url都会被scrapy框架进行get请求的发送
start_urls = ["https://www.cnblogs.com/"]
# 实现数据解析
# 参数response表示请求对应的响应对象
# parse方法调用的次数取决于请求的次数
def parse(self, response):
# 可以在响应对象中直接使用xpath进行数据解析
pass
【三】CSS解析器
【1】概览
- response.css(‘a’)返回的是selector对象,
- response.css(‘a’).extract()返回的是a标签对象
- response.css(‘a::text’).extract_first()返回的是第一个a标签中文本的值
- response.css(‘a::attr(href)’).extract_first()返回的是第一个a标签中href属性的值
- response.css(‘a[href*=image]::attr(href)’).extract()返回所有a标签中href属性包含image的值
- response.css(‘a[href*=image] img::attr(src)’).extract()返回所有a标签下image标签的src属性
【2】基本语法
语法 | 说明 |
---|---|
* | 选择所有节点 |
#container | 选择id为container的节点 |
.container | 选择所有class包含container的节点 |
div,p | 选择所有 div 元素和所有 p 元素 |
li a | 选取所有li 下所有a节点 |
ul + p | 选取ul后面的第一个p元素 |
div#container > ul | 选取id为container的div的第一个ul子元素 |
ul ~p | 选取与ul相邻的所有p元素 |
a[title] | 选取所有有title属性的a元素 |
a[href=”http://baidu.com”] | 选取所有href属性为http://baidu.com的a元素 |
a[href*=”baidu”] | 选取所有href属性值中包含baidu的a元素 |
a[href^=”http”] | 选取所有href属性值中以http开头的a元素 |
a[href$=”.jpg”] | 选取所有href属性值中以.jpg结尾的a元素 |
input[type=radio]:checked | 选择选中的radio的元素 |
div:not(#container) | 选取所有id为非container 的div属性 |
li:nth-child(3) | 选取第三个li元素 |
li:nth-child(2n) | 选取第偶数个li元素 |
a::attr(href) | 选取a标签的href属性 |
a::text | 选取a标签下的文本 |
【3】更多语法
- 选择器是一种模式,用于选择需要添加样式的元素。
- CSS列指示该属性是在哪个 CSS 版本中定义的。(CSS1、CSS2 还是 CSS3)
选择器 | 例子 | 例子描述 |
---|---|---|
.class | .intro | 选择 class=”intro” 的所有元素。 |
#id | #firstname | 选择 id=”firstname” 的所有元素。 |
* | * | 选择所有元素。 |
element | p | 选择所有 元素。 |
element,element | div,p | 选择所有 元素和所有 元素。 |
element element] | div p | 选择元素内部的所有 元素。 |
element>element | div>p | 选择父元素为 元素的所有 元素。 |
element+element | div+p | 选择紧接在元素之后的所有 元素。 |
[attribute] | [target] | 选择带有 target 属性所有元素。 |
[attribute=value] | [target=_blank] | 选择 target=”_blank” 的所有元素。 |
[attribute~=value] | [title~=flower] | 选择 title 属性包含单词 “flower” 的所有元素。 |
[attribute|=value] | [lang|=en] | 选择 lang 属性值以 “en” 开头的所有元素。 |
:link | a:link | 选择所有未被访问的链接。 |
:visited | a:visited | 选择所有已被访问的链接。 |
:active | a:active | 选择活动链接。 |
:hover | a:hover | 选择鼠标指针位于其上的链接。 |
:focus | input:focus | 选择获得焦点的 input 元素。 |
:first-letter | p:first-letter | 选择每个 元素的首字母。 |
:first-line | p:first-line | 选择每个 元素的首行。 |
:first-child | p:first-child | 选择属于父元素的第一个子元素的每个 元素。 |
:before | p:before | 在每个 元素的内容之前插入内容。 |
:after | p:after | 在每个 元素的内容之后插入内容。 |
:lang(language) | p:lang(it) | 选择带有以 “it” 开头的 lang 属性值的每个 元素。 |
element1~element2 | p~ul | 选择前面有 元素的每个
|
[attribute^=value] | a[src^=”https”] | 选择其 src 属性值以 “https” 开头的每个 元素。 |
[attribute$=value] | a[src$=”.pdf”] | 选择其 src 属性以 “.pdf” 结尾的所有 元素。 |
[attribute*=value] | a[src*=”abc”] | 选择其 src 属性中包含 “abc” 子串的每个 元素。 |
:first-of-type | p:first-of-type | 选择属于其父元素的首个 元素的每个 元素。 |
:last-of-type | p:last-of-type | 选择属于其父元素的最后 元素的每个 元素。 |
:only-of-type | p:only-of-type | 选择属于其父元素唯一的 元素的每个 元素。 |
:only-child | p:only-child | 选择属于其父元素的唯一子元素的每个 元素。 |
:nth-child(n) | p:nth-child(2) | 选择属于其父元素的第二个子元素的每个 元素。 |
:nth-last-child(n) | p:nth-last-child(2) | 同上,从最后一个子元素开始计数。 |
:nth-of-type(n) | p:nth-of-type(2) | 选择属于其父元素第二个 元素的每个 元素。 |
:nth-last-of-type(n) | p:nth-last-of-type(2) | 同上,但是从最后一个子元素开始计数。 |
:last-child | p:last-child | 选择属于其父元素最后一个子元素每个 元素。 |
:root | :root | 选择文档的根元素。 |
:empty | p:empty | 选择没有子元素的每个 元素(包括文本节点)。 |
:target | #news:target | 选择当前活动的 #news 元素。 |
:enabled | input:enabled | 选择每个启用的 元素。 |
:disabled | input:disabled | 选择每个禁用的 元素 |
:checked | input:checked | 选择每个被选中的 元素。 |
:not(selector) | :not(p) | 选择非 元素的每个元素。 |
::selection | ::selection | 选择被用户选取的元素部分。 |
【四】Xpath解析器
【1】概览
- Scrapy xpath语法,Xpath是XML Path的简介,基于XML树状结构,可以在整个树中寻找锁定目标节点。由于HTML文档本身就是一个标准的XML页面,因此我们可以使用XPath的语法来定位页面元素。
【2】路径表达式
表达式 | 描述 | 实例 |
---|---|---|
nodename | 选取nodename节点的所有子节点 | //div |
/ | 从根节点选取 | /div |
// | 选取任意位置的节点,不考虑他们的位置 | //div |
. | 选取当前节点 | ./div |
.. | 选取当前节点的父节点 | .. |
@ | 选取属性 | //@calss |
- 示例
语法 | 说明 |
---|---|
artical | 选取所有artical元素的子节点 |
/artical | 选取根元素artical |
./artical | 选取当前元素下的artical |
../artical | 选取父元素下的artical |
artical/a | 选取所有属于artical的子元素a元素 |
//div | 选取所有div 子元素,无论div在任何地方 |
artical//div | 选取所有属于artical的div 元素,无论div元素在artical的任何位置 |
//@class | 选取所有class属性 |
a/@href | 选取a标签的href属性 |
a/text() | 选取a标签下的文本 |
string(.) | 解析出当前节点下所有文字 |
string(..) | 解析出父节点下所有文字 |
【3】谓语
- 谓语被嵌在方括号内,用来查找某个特定的节点或包含某个制定的值的节点
语法 | 说明 |
---|---|
/artical/div[1] | 选取所有属于artical 子元素的第一个div元素 |
/artical/div[last()] | 选取所有属于artical子元素的最后一个div元素 |
/artical/div[last()-1] | 选取所有属于artical子元素的倒数第2个div元素 |
/artical/div[position()❤️] | 选取所有属于artical子元素的前2个div元素 |
//div[@class] | 选取所有拥有属性为class的div节点 |
//div[@class=”main”] | 选取所有div下class属性为main的div节点 |
//div[price>3.5] | 选取所有div下元素值price大于3.5的div节点 |
【4】通配符
- Xpath通过通配符来选取未知的XML元素
表达式 | 结果 |
---|---|
//* | 选取所有元素 |
//div/* | 选取所有属于div元素的所有子节点 |
//div[@*] | 选取所有带属性的元素 |
【5】 取多个路径
- 使用 | 运算符可以选取多个路径
表达式 | 结果 |
---|---|
//div | //table | 选取文档中所有的div和table节点 |
//div/a | //div/p | 选取所有div元素的a和p 元素 |
artical/div/pl | //span | 选取所有div下的pl和文档中所有span |
【6】轴
- 轴可以定义相对于当前节点的节点集
轴名称 | 表达式 | 描述 |
---|---|---|
ancestor | ./ancestor:
标签:novel,滑块,img,self,验证码,Scrapy,article,div,scrapy
From: https://www.cnblogs.com/zyb123/p/18316818
相关文章
|