20200225 爬虫-bs4使用及简单代理破解验证码
目录
昨日回顾
## 1 什么是爬虫?
## 2 爬虫的流程
发送http请求----》别人服务器响应----》拿到响应自己解析(re、bs4、lxml)------》入库(mongodb)
分布式爬虫---redis(blpop/brpop:列表,阻塞队列)
集群和分布式:单实例的项目
集群化的部署:一个项目部署在多台机器上
分布式(微服务):一个项目拆成多个部分,放到不同的服务器上,每个项目单独开发,单独上线
## 3 requests模块
模拟发送http请求
```python
# 1 可以发送任意请求get,post,delete。。。
requests.get()
requests.post()
# 2 携带头信息
#user-agent referer cookie(cookie池)
requests.get(headers={})
# 3 cookie单独拿出来
requests.get(cookies={})
# 4 get请求携带参数两种方式
# 5 post请求请求体 data/json
# 6 响应对象response 有好多属性
# 7 发送请求,使用代理,随机取一个代理,在列表中通过random
# 8 ssl,timeout,上传文件(项目)
1.链式调用
```
在方法中实现 返回自己
return self
即可实现一直...属性
```
2.bs4的搜索文档树的find有几种方式可以查找标签
```
五种过滤器
字符串
soup.find(name='标签名',attrs={'属性':'值'})
列表
soup.findall(name=['标签名','标签2'])
正则
使用re.compile('正则规则')
bool
soup.findall(id=true)
方法
定义方法
sopu.find_all(方法)
```
3.bs4获取标签属性的方式
```
直接.
标签.name
p['class']
p.attrs.get('class')
```
4.bs4获取标签内容的三种方式,有什么不同
```
text : 获取所有的文本,包括子标签的文字
string : 获取当前第一级目录的文字
strings : 获得一个生成器,每层文字放在列表中
```
5.你验证码如何破解
```
打码平台申请调用接口
```
bs4
简介
安装
pip install beautifulsoup4
导入
from bs4 import BeautifulSoup4
参数
# 实例化得到对象
soup = beautifulsoup(ret.text,'lxml')
'''
第一个参数 可以是字符串,或者文件对象
第二个参数 解析的方式(解析库)
html.parser # python自带的
lxml # 需要另外安装解析库 pip install lxml
'''
使用
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>
"""
# 实例化得到对象
soup = BeautifulSoup(html_doc,'lxml')
# 美化,对标签进行闭合
# soup.prettify()
1 遍历文档树
# 用法: 直接 . 取下一个标签
p = soup.p
print(p) # 对象 <p class="title"><b>The Dormouse's story</b></p>
基本使用
# 获取标签的名称
print(p.name) # p
# 获取标签的属性
# 当你获取class的时候,获取的是列表
print(p['class']) # ['title']
print(p.attrs.get('class')) # ['title']
# 获取标签的内容
# text: 获取所有的文字,包括子标签的文字
# string: 获取当前第一级目录的文字,如果嵌套多层,就取不出文字
# strings: 获取一个生成器,每层文字分别放在列表中
p = soup.body.p
print(p.text) # The Dormouse's story
print(p.string) # The Dormouse's story
print(p.strings) # <generator object _all_strings at 0x00000206A5DE3A98>
print(list(p.strings)) # ["The Dormouse's story"]
用的较少(了解)
# 嵌套选择
p = soup.body.p
# 子节点,子孙节点
# 子节点
print(soup.body.p.contents) # [<b>The Dormouse's story</b>]
# 子孙节点
print(soup.body.p.children) # <list_iterator object at 0x0000014DDE79CF60>
print(list(soup.body.p.children)) # [<b>The Dormouse's story</b>]
# 子子孙孙
print(list(soup.body.p.descendants)) # [<b>The Dormouse's story</b>]
# 父节点,祖先节点
print(soup.body.p.parent) # 直接父节点
print(soup.body.p.parents) # 所有父集,祖先的节点 生成器
# 兄弟节点
print(soup.a.next_sibling) # 下一个兄弟
print(soup.a.previous_sibling) # 上一个兄弟
2.搜索文档树
搜索的查找速度比遍历低
find()与find_all()
- 五种过滤器 : 字符串,列表,正则,bool,方法
# 字符串: 精准匹配
# 属性查找的方式一
p = soup.find(name='p',class_='story') # p是标签对象,和soup是一样的
print(p)
# 属性查找方式二
p = soup.find(name='p',attrs={'class':'story'})
print(p)
# 列表查
ret = soup.find_all(name=['p','a'])
ret = soup.find_all(id=['id_1','link1'])
print(ret)
# 正则 re.compile()
import re
ret = soup.find_all(name=re.compile('^b')) # 查找名字以b开头的标签
# bool布尔
ret = soup.find_all(id=True) # 查找所有有ID的标签
# 方法
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
# 查找有class属性没有id属性的
ret = soup.find_all(has_class_but_no_id)
print(ret)
联合使用
# 取属性,取文字
# tag对象['src'] tag对象.attrs.get('src')
# tag对象.text string
# 遍历文档树和搜索文档树可以同时用
soup.body.find(name='p').b
soup.body.find(name='p').find(id='link')
# tag对象与beautifulsoup对象用起来完全一样
soup = BeautifulSoup(html_doc,'lxml')
print(type(soup))
body = soup.body
print(type(body))
3.拓展
链式调用
跟语言没关系jq
# 链式调用在python中如何实现? 点多少次,其实还是对象本身
class A:
# 每个函数返回self,把对象本身返回
def test(self,name):
self.name = name
return self
def test2(self,age):
self.age = age
return self
a =A()
x = a.test('小明').test2(18)
print(x.age) # 18
# 每个函数返回self,把对象本身返回
bs4 其他用法
# limit 限制查找的个数
ret = soup.find_all(name='p',limit=1)
print(ret) # [<p class="title"><b>The Dormouse's story</b></p>]
# recursive 是否递归查找
ret = soup.find_all(name='p',recursive=False) # 只找同级的标签
ret = soup.find_all(name='p',recursive=True) # 子孙的都找
print(ret)
3.css选择
# select 方法中写css选择器
ret = soup.select('.title')
ret = soup.select('#link1') # 查找id为link1的标签
# 重点 > 与 空格 的区别 (>选择子元素,空格选择子孙中的)
ret = soup.select('.title>b') # 查找class是title标签下的子元素b标签
ret = soup.select('.title b') # 查找class是title标签下的子元素或子孙中的b元素
使用select提取出的元素如果是Tag标签,
可以使用属性a['herf'] 和名称提取,
还可以使用.string .stripped_strings .strings .get_text() 获取内容
4.xpath选择(BeautifulSoup4没有xpath选择)
XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。
XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。
因此,对 XPath 的理解是很多高级 XML 应用的基础。
代理池的搭建
# 收费: 稳定
网站注册,向该网站的api接口发送请求,获取IP
# 免费:
自己搭建:flask框架搭建服务,后台用爬虫(requests爬取免费),放入redis
访问127.0.0.1/get 随机给一个ip代理
# 网上开源的:
#1 下载下来,打开
#2 安装依赖 pip3 install -r requirements.txt
#3 修改配置文件Config/setting.py
35行左右,意思是爬取的代理放到redis中,
DB_TYPE = getenv('db_type', 'redis').upper()
DB_HOST = getenv('db_host', '127.0.0.1')
DB_PORT = getenv('db_port', 6379)
DB_PASSWORD = getenv('db_password', '')
#4 跑项目 可以在cli目录下通过ProxyPool.py启
python3 proxyPool.py schedule:爬取代理
python3 proxyPool.py webserver:启动服务
#5 测试
http://127.0.0.1:5010/get/ 发一次,取一个代理ip
验证码的破解
花钱,从网上的验证码图片,传给它,他就给你识别,(12306的验证码,模拟登陆12306)
-超级鹰
-模拟登陆某些网站
-http://www.chaojiying.com/price.html
# 注册用户
# 创建软件
# 充值
# 下载demo
# 修改demo,账号密码该上
# 运行代码
-云打码
案例
爬取汽车之家新闻
# 爬取汽车之家新闻
# pip3 install beautifulsoup4
# pip3 install lxml
import requests
# 引入
from bs4 import BeautifulSoup
for i in range(1,10):
ret = requests.get('https://www.autohome.com.cn/news/%s/#liststart'%i)
ret.encoding = 'gbk'
# print(ret.text)
# 实例化得到对象(
# 第一个参数,可以是字符串,或者是文件对象
# 第二个参数,解析的方式(html.parser lxml)
soup = BeautifulSoup(ret.text, 'lxml')
# 以后查找属性,都是操作soup这个对象
# 查找文档树之查找所有
# div=soup.find_all(name='div',id='auto-channel-lazyload-article')[0]
# #查找div下的ul标签
# ul=div.find_all(name='ul')
# print(ul)
# class是一个关键字
ul = soup.find(name='ul', class_='article')
# 找到ul下所有的li标签
li_list = ul.find_all(name='li')
# 循环列表
for li in li_list:
img = li.find(name='img')
if img:
# 获取标签的属性两种方式
# img_ul=img['src']
img_ul = 'http:' + img.attrs.get('src')
title = li.find(name='h3').text
desc = li.find('p').text
url = 'http:' + li.find(name='a')['href']
# print(img_ul)
# print(title)
# print(desc)
# print(url)
#图片保存
img_name=img_ul.rsplit('/',1)[-1]
ret2=requests.get(img_ul)
with open(img_name,'wb') as f:
for line in ret2.iter_content():
f.write(line)
print('''
文章标题:%s
文章链接:%s
文章图片地址:%s
文章摘要:%s
'''%(title,url,img_ul,desc))
#总结:bs4 查找文档树
# 标签对象=soup.find(name='div',href='',class_='')
# 标签对象可以继续使用find
# 获取属性两种方式 标签对象['属性名'] 标签对象.attrs.get('属性名')
# 获取文本 标签对象.text