扩大
缩小
人生本来就短暂,为什么还要栽培苦涩。
返回顶部

爬虫

爬虫

爬虫一:自学内容

# 1 爬虫介绍
# 2 requests模块
# 3 爬一个视频网站
# 4 模拟登陆某网站
# 5 bs4
# 6 汽车之家新闻
# 7 selenium
# 8 京东商品信息
# 9 代理池,cookie池
# 10 验证码破解(打码平台)
# 11 自动登陆到12306,拿到cookie
# 12 抓包工具的使用fillder(app爬取)
# 13 scarpy框架,持久化,整站爬取,集成selenium,代理池,UA
# 14 分布式爬虫,scrapy-redis
# 15 Mongodb

1 爬虫介绍

# 1 本质:模拟发送http请求(requests)----》解析返回数据(re,bs4,lxml,json)---》入库(redis,mysql,mongodb)
# 2 app爬虫:本质一模一样
# 3 为什么python做爬虫最好:包多,爬虫框架:scrapy:性能很高的爬虫框架,爬虫界的django,大而全(爬虫相关的东西都集成了)
# 4 百度,谷歌,就是个大爬虫  在百度搜索,其实是去百度的服务器的库搜的,百度一直开着爬虫,一刻不停的在互联网上爬取,把页面存储到自己库中
# 5 全文检索:全文检索


# 10 你公司里可以做项目,爬虫爬回来的(律师行业),搭一个搜索网站(app,小程序),
# 11 医疗行业:造药企业,头孢类的
# 12 爬简历:简历库


#面试很重要:http协议(80%被问到)
# 特点
(1)应用层协议(mysql,redis,mongodb:cs架构的软件:Navicat,python代码:pymysql,都是mysql客户端--socket:自己定制的协议----》服务端)(docker,es---》http(resful)---》服务端)
(2)基于请求-响应模式:
		客户端主动发起请求---》服务端才能响应   (服务端不能主动推送消息:轮询,长轮询,websocket协议:主动推送消息)
(3)无状态保存(cookie,session,token:)
(4)无连接:发送一次请求,响应完就断开,性能影响(http协议版本:0.9,1.1:多次请求,共用一个socket连接,2.0:
    一次请求,可以携带多个http请求)
    
# http请求:请求首行,请求头,请求体
	-127.0.0.1/name=lqz&age=18:请求首行
  -post请求请求体中放数据:name=lqz&age=18  放在请求体中
  	-post请求,可以这样发么:127.0.0.1/name=lqz&age=18,django数据requtes.GET
    -放在体中的:request.POST
    -请求体的格式(编码格式):
      urlencode:name=lqz&age=18   ---》request.POST
      json:{name:lqz,age:18}     ---->request.POST取不出来(为什么?django框架没有做这个事)
      formdata:传文件,5g大文件,    ----》request.POST
# http响应:
	# 响应首行:状态码:1,2,3,4,5   301和302的区别
  # 响应头:key:value:背几个响应头
  	-cookie:
    -cache-control:缓存控制
  # 响应体:
  	html,json
    
# 浏览器调试
	-右键--》调试模式
  -elements:响应体,html格式
  -console:调试窗口(js输出的内容,在这能看到)
  -network:发送的所有请求,all  xhr:ajax请求
    
    

2 requests模块

# 1 模块:可以模拟发送http请求,urlib2:内置库,不太好用,繁琐,封装出requests模块,应用非常广泛(公司,人)
# 2 pip3 install requests
# 3 小插曲:requests作者,众筹换电脑(性能跟不上了),捐钱(谷歌公司捐了),2 万 8 千美元,买了游戏设备,爆料出来,骗捐,辟谣
# 1 request模块基本使用

import requests

# # 发送http请求
# # get,delete,post。。本质都是调用request函数
# ret=requests.get('https://www.cnblogs.com')
# print(ret.status_code) # 响应状态码
# print(ret.text)  # 响应体,转成了字符串
# print(ret.content) # 响应体,二进制
# ret=requests.post()\
# ret=requests.request("get",)
# ret=requests.delete()

# 2 get 请求带参数
# 方式一
# ret = requests.get('https://www.baidu.com/',
#                    headers={
#                        # 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',
#                        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36'
#                    })
# print(ret.text)
# 方式2(建议用方式二)中文会自动转码
# ret=requests.get('http://0.0.0.0:8001/',params={'name':"美女",'age':18})
# print(ret.text)


# 3 带headers
# ret = requests.get('http://0.0.0.0:8001/?name=%E7%BE%8E%E5%A5%B3',
#                    headers={
#                        # 标志,什么东西发出的请求,浏览器信息,django框架,从哪取?(meta)
#                        'User-Agent': 'request',
#                        # 上一个页面的地址,图片防盗链
#                        'Referer': 'xxx'
#                    })
# print(ret)

# 图片防盗链:如果图片的referer不是我自己的网站,就直接禁止掉
# <img src="https://www.lgstatic.com/lg-community-fed/community/modules/common/img/avatar_default_7225407.png">


# 4 带cookie,随机字符串(用户信息:也代表session),不管后台用的token认证,还是session认证
# 一旦登陆了,带着cookie发送请求,表示登陆了(下单,12306买票,评论)
# 第一种方式
# ret = requests.get('http://0.0.0.0:8001/?name=%E7%BE%8E%E5%A5%B3',
#                    headers={
#                        'cookie': 'key3=value;key2=value',
#                    })
# 第二种方式
# ret = requests.get('http://0.0.0.0:8001/?name=%E7%BE%8E%E5%A5%B3',
#                    cookies={"islogin":"xxx"})
# print(ret)

# 5 发送post请求(注册,登陆),携带数据(body)
#data=None, json=None
# data:urlencoded编码
# ret=requests.post('http://0.0.0.0:8001/',data={'name':"lqz",'age':18})
# json:json编码
# import json
# data=json.dumps({'name':"lqz",'age':18})
# ret=requests.post('http://0.0.0.0:8001/',json=data)
# print(ret)
# 注意:编码格式是请求头中带的,所有我可以手动修改,在headers中改

# 6 session对象
# session=requests.session()
# # 跟requests.get/post用起来完全一样,但是它处理了cookie
# # 假设是一个登陆,并且成功
# session.post()
# # 再向该网站发请求,就是登陆状态,不需要手动携带cookie
# session.get("地址")


# 7 响应对象
# print(respone.text)   # 响应体转成str
# print(respone.content) # 响应体二进制(图片,视频)
#
# print(respone.status_code) # 响应状态码
# print(respone.headers) # 响应头
# print(respone.cookies) # 服务端返回的cookie
# print(respone.cookies.get_dict()) # 转成字典
# print(respone.cookies.items())
#
# print(respone.url)  # 当次请求的地址
# print(respone.history) # 如果有重定向,放到一个列表中
# ret=requests.post('http://0.0.0.0:8001/')
# ret=requests.get('http://0.0.0.0:8001/admin')
# #不要误解
# ret=requests.get('http://0.0.0.0:8001/user')
# print(ret.history)

# print(respone.encoding) # 编码方式

#response.iter_content() # 视频,图片迭代取值
# with open("a.mp4",'wb') as f:
#     for line in response.iter_content():
#         f.write(line)


# 8 乱码问题
# 加载回来的页面,打印出来,乱码(我们用的是utf8编码),如果网站用gbk,
# ret.encoding='gbk'
# ret=requests.get('http://0.0.0.0:8001/user')
# # ret.apparent_encoding当前页面的编码
# ret.encoding=ret.apparent_encoding


# 9 解析json
# 返回数据,有可能是json格式,有可能是html格式
# ret=requests.get('http://0.0.0.0:8001/')
# print(type(ret.text))
# print(ret.text)
#
# a=ret.json()
# print(a['name'])
# print(type(a))

# 10 使用代理
# 正向代理
# django如何拿到客户端ip地址 META.get("REMOTE_ADDR")
# 如何去获取代理,如何使用(用自己项目验收)
# 使用代理有什么用
# ret=requests.get('http://0.0.0.0:8001/',proxies={'http':'地址'})
# print(type(ret.text))
# print(ret.text)

# 11 异常处理
# 用try except捕获一下 就用它就型了:Exception

# 12 上传文件(爬虫用的比较少,后台写服务,)
# file={'myfile':open("1.txt",'rb')}
# ret=requests.post('http://0.0.0.0:8001/',files=file)
# print(ret.content)


# 认证,处理ssl(不讲了)

3 代理

## 代理
# 网上会有免费代理,不稳定

# 使用代理有什么用?
# drf:1分钟只能访问6次,限制ip
# 每次发请求都使用不同代理,random一下
# 代理池:列表,其实就是代理池的一种
import requests
# ret=requests.get('https://www.cnblogs.com/',proxies={'http':'222.85.28.130:40505'})

#高匿:服务端,根本不知道我是谁
#普通:服务端是能够知道我的ip的
# http请求头中:X-Forwarded-For:代理的过程
# ret=requests.get('http://101.133.225.166:8080',proxies={'http':'222.85.28.130:40505'})
# ret=requests.get('http://101.133.225.166:8080',proxies={'http':'114.99.54.65:8118'})
# print(ret.text)

4 爬视频

############
# 2 爬取视频
#############
#categoryId=9 分类id
#start=0 从哪个位置开始,每次加载12个
# https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=9&start=0

import requests
import re
ret=requests.get('https://www.pearvideo.com/category_loading.jsp?reqType=5&categoryId=9&start=0')
# print(ret.text)
# 正则取解析
reg='<a href="(.*?)" class="vervideo-lilink actplay">'
video_urls=re.findall(reg,ret.text)
print(video_urls)
for url in video_urls:
    ret_detail=requests.get('https://www.pearvideo.com/'+url)
    reg='srcUrl="(.*?)",vdoUrl=srcUrl'
    mp4_url=re.findall(reg,ret_detail.text)[0] #type:str
    # 下载视频
    video_content=requests.get(mp4_url)
    video_name=mp4_url.rsplit('/',1)[-1]
    with open(video_name,'wb') as f:
        for line in video_content.iter_content():
            f.write(line)




5 自动登录网站

############
# 3 模拟登陆某网站
#############

import requests

ret = requests.post('http://www.aa7a.cn/user.php',
                    data={
                        'username': '616564099@qq.com',
                        'password': 'lqz123',
                        'captcha': 'f5jn',
                        'remember': '1',
                        'ref': 'http://www.aa7a.cn/',
                        'act': 'act_login',
                    })
cookie=ret.cookies.get_dict()
print(cookie)
# 如果不出意外,咱么就登陆上了,再向首页发请求,首页返回的数据中就有616564099@qq.com
ret1=requests.get('http://www.aa7a.cn/',cookies=cookie)
# ret1=requests.get('http://www.aa7a.cn/')

print('616564099@qq.com' in ret1.text)


# 秒杀小米手机,一堆小号
# 定时任务:一到时间,就可以发送post请求,秒杀手机


# 以后碰到特别难登陆的网站,代码登陆不进去怎么办?

# 之所以要登陆,就是为了拿到cookie,下次发请求(如果程序拿不到cookie,自动登陆不进去)
# 就手动登陆进去,然后用程序发请求

爬虫二:

昨日回顾

# 1 爬虫基本原理:发送http请求(requests)----》拿到数据(html,json)(re,bs4)---》入库(文件,excel,mysql,redis,mongodb)
# 2 爬虫协议:哪部分允许你爬,哪部分不允许:robots.txt,爬数据的时候,一定要注意速度
# 3 http回顾,应用层协议,请求协议和响应协议
# 4 requests模块:基于urlib封装的
# 5 基本使用 requests.get/post----》本质都是调用requests.request 函数
# 6 get请求携带参数(两种方式)
# 7 发送请求携带header(ua,referer,。。。。)
# 8 携带cookie 两种方式(放到头中,cookies={})
# 9 发送post请求,携带数据(data,json)
# 10 响应对象属性和方法 response对象
# 11 返回数据是json格式,json()--》直接转成字典
# 12 代理 ,普通,高匿,使用代理的方式,自己搭一个简单的代理池(列表)
# 13 超时,异常
# 14 上传文件
image-20200408085753901

今日内容

1 requests+bs4爬汽车之家新闻

# 今日头条 
# https://www.autohome.com.cn/news/1/#liststart


######
#2  爬取汽车之家新闻
######

import requests

# 向汽车之家发送get请求,获取到页面
ret=requests.get('https://www.autohome.com.cn/news/1/#liststart')
# ret.encoding='gb2312'
# print(ret.text)

# bs4解析(不用re了)
# 安装 pip3 install beautifulsoup4
# 使用
from bs4 import BeautifulSoup
# 实例化得到对象,传入要解析的文本,解析器
# html.parser内置解析器,速度稍微慢一些,但是不需要装第三方模块
# lxml:速度快一些,但是需要安装 pip3 install lxml
soup=BeautifulSoup(ret.text,'html.parser')
# soup=BeautifulSaoup(open('a.html','r'))
# find(找到的第一个)
# find_all(找到的所有)
# 找页面所有的li标签
li_list=soup.find_all(name='li')
for li in  li_list:
    # li是Tag对象
    # print(type(li))
    h3=li.find(name='h3')
    if not h3:
        continue

    title=h3.text
    desc=li.find(name='p').text
    # 对象支持[]取值,为什么?重写了__getitem__魔法方法
    # 面试题:你使用过的魔法方法?
    img=li.find(name='img')['src']# type:str
    url=li.find(name='a')['href']
    # 图片下载到本地
    ret_img=requests.get('https:'+img)
    img_name=img.rsplit('/',1)[-1]
    with open(img_name,'wb') as f:
        for line in ret_img.iter_content():
            f.write(line)
    print('''
    新闻标题:%s
    新闻摘要:%s
    新闻链接:%s
    新闻图片:%s
    '''%(title,desc,url,img))




2 bs4的使用(遍历文档树和查找文档树)

# 1 从html或者xml中提取数据的python库,修改xml
# 补充:java,配置文件基本都是xml格式,以后可能会用python修改配置文件(自动化运维平台,devops平台),mycat,自动上线,自动安装软件,配置,查看nginx日志
# 视频,生鲜,crm,鲜果配送,在线教育,cmdb      ---》(sugo平台)
# 飞猪 (旅游相关)    毒app     兔女郎


遍历文档树

from bs4 import BeautifulSoup
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"id="id_p"><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>
"""
# pip3 install lxml
soup=BeautifulSoup(html_doc,'lxml')
# 美化
# print(soup.prettify())

# 遍历文档树
#1、用法(通过.来查找,只能找到第一个)
# Tag对象
# head=soup.head
# title=head.title
# # print(head)
# print(title)

# p=soup.p
# print(p)
#2、获取标签的名称
#Tag对象
# p=soup.body
# print(type(p))
from  bs4.element import Tag
# print(p.name)

#3、获取标签的属性
# p=soup.p
# 方式一
# 获取class属性,可以有多个,拿到列表
# print(p['class'])
# print(p['id'])
# print(p.get('id'))
# 方式二
# print(p.attrs['class'])
# print(p.attrs.get('id'))
#4、获取标签的内容
# p=soup.p
# print(p.text) # 所有层级都拿出来拼到一起
# print(p.string) # 只有一层,才能去除
# print(list(p.strings)) # 把每次都取出来,做成一个生成器
#5、嵌套选择
# title=soup.head.title
# print(title)
#6、子节点、子孙节点
# p1=soup.p.children   # 迭代器
# p2=soup.p.contents  # 列表
# print(list(p1))
# print(p2)
#7、父节点、祖先节点
# p1=soup.p.parent  # 直接父节点
# p2=soup.p.parents
# print(p1)
# # print(len(list(p2)))
# print(list(p2))
#8、兄弟节点
# print(soup.a.next_sibling) #下一个兄弟
# print(soup.a.previous_sibling) #上一个兄弟
#
# print(list(soup.a.next_siblings)) #下面的兄弟们=>生成器对象
# print(soup.a.previous_siblings) #上面的兄弟们=>生成器对象

查找文档树

# 查找文档树(find,find_all),速度比遍历文档树慢
# 两个配合着使用(soup.p.find())
# 五种过滤器: 字符串、正则表达式、列表、True、方法
# 以find为例
#1 字符串查找 引号内是字符串
# p=soup.find(name='p')
# p=soup.find(name='body')
# print(p)
# 查找类名是title的所有标签,class是关键字,class_
# ret=soup.find_all(class_='title')
# href属性为http://example.com/elsie的标签
# ret=soup.find_all(href='http://example.com/elsie')
# 找id为xx的标签
# ret=soup.find_all(id='id_p')
# print(ret)

#2 正则表达式
# import re
# # reg=re.compile('^b')
# # ret=soup.find_all(name=reg)
# #找id以id开头的标签
# reg=re.compile('^id')
# ret=soup.find_all(id=reg)
# print(ret)

# 3 列表
# ret=soup.find_all(name=['body','b'])
# ret=soup.find_all(id=['id_p','link1'])
# ret=soup.find_all(class_=['id_p','link1'])
# and 关系
# ret=soup.find_all(class_='title',name='p')
# print(ret)


#4  True
# 所有有名字的标签
# ret=soup.find_all(name=True)
#所有有id的标签
# ret=soup.find_all(id=True)
# 所有有herf属性的
# ret=soup.find_all(href=True)
# print(ret)

# 5 方法
# def has_class_but_no_id(tag):
#     return tag.has_attr('class') and not tag.has_attr('id')
#
# print(soup.find_all(has_class_but_no_id))

# 6 其他使用
# ret=soup.find_all(attrs={'class':"title"})
# ret=soup.find_all(attrs={'id':"id_p1",'class':'title'})
# print(ret)

# 7 拿到标签,取属性,取text
# ret=soup.find_all(attrs={'id':"id_p",'class':'title'})
# print(ret[0].text)

# 8 limit(限制条数)
# soup.find()  就是find_all limit=1
# ret=soup.find_all(name=True,limit=2)
# print(len(ret))

# 9 recursive
# recursive=False (只找儿子)不递归查找,只找第一层
# ret=soup.body.find_all(name='p',recursive=False)
# print(ret)

3 带你搭一个免费的代理池

# https://github.com/jhao104/proxy_pool
# 收费的:提供给你一个接口,每掉一次这个接口,获得一个代理
# 免费:用爬虫爬取,免费代理,放到我的库中,flask,django搭一个服务(删除代理,自动测试代理可用性),每次发一个请求,获取一个代理

# 带你配置

# 1 下载,解压,用pycharm打开
# 2 安装依赖 pip install -r requirements.txt
# 3 配置Config/setting.py:
	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 本地启动redis-server

# 5 可以在cli目录下通过ProxyPool.py
	-python proxyPool.py schedule :调度程序,他会取自动爬取免费代理
  -python proxyPool.py webserver:启动api服务,把flask启动起来

4 验证码破解

# 1 简单验证码,字母,数字
# 2 高级的,选择,你好,12306选择乒乓球,滑动验证(极验)

# 打码平台(自动破解验证码,需要花钱)云打码,超级鹰(12306)
http://www.yundama.com/
http://www.chaojiying.com/

# 注册账号,(充钱)把demo下载下来,运行即可

5 爬取糗事百科段子,自动通过微信发给女朋友(老板)

## 6 爬取拉钩职位
## 7 爬取cnblogs新闻
## 8 爬取红楼梦小说写入txt
```
http://www.shicimingju.com/book/hongloumeng.html
```
## 9 爬取糗事百科段子,自动通过微信发给女朋友(老板)
## 10 肯德基餐厅信息
http://www.kfc.com.cn/kfccda/storelist/index.aspx
#####
# 1 爬取糗事百科,微信自动发送
#####
# https://www.qiushibaike.com/text/
# https://www.qiushibaike.com/text/page/1/

import requests
from bs4 import BeautifulSoup
ret=requests.get('https://www.qiushibaike.com/text/page/1/')
# print(ret.text)
ll=[]
soup=BeautifulSoup(ret.text,"lxml")
article_list=soup.find_all(name='div',id=True,class_='article')
for article in article_list:
    content=article.find(name='div',class_='content').span.text
    # content=article.find(name='div',class_='content').text
    # content=article.find(class_='content').text
    # print(content)
    # 入库
    #我们放到列表中
    ll.append(content)
print(ll)

# 微信自动发消息
# wxpy:实现了web微信的接口
# pip3 install wxpy
from wxpy import *
# 实例化得到一个对象,微信机器人对象
import random
bot=Bot(cache_path=True)

@bot.register() # 接收从指定好友发来的消息,发送者即recv_msg.sender为指定好友girl_friend
def recv_send_msg(recv_msg):
    print('收到的消息:',recv_msg.text) # recv_msg.text取得文本
    return random.choice(ll)

embed()

爬虫三:

昨日回顾

# 1 requests+beautifulsoup4,汽车之家(find(name="li"))
		-汽车资讯类的搜索引擎
# 2 bs4的简单使用:在html/xml中查找元素的模块(查找,修改)
# 3 遍历文档树 . 只能找到一个(速度快)
# 4 获取属性(Tag对象.attrs['href'])(Tag对象['href'])
# 5 text,string,strings
# 6 获取标签名字,子孙,父亲,兄弟
# 7 查找文档树:find和find_all   (limit)
# 8 5种过滤器:字符串,列表,true,正则,方法
	-find_all(name="字符串",href="字符串",id='',class_="字符串")
  -find_all(attrs={'name':'字符串'})
# 9 糗事百科,拉钩,cnblogs文章 

# 10 反扒:头信息,ua,referer,当前时间 time.time(),
	-请求体中设置加密的东西:xxx:(id+时间戳+xxx)加密算法加密   js:加密算法
  -杏树林:app+(前后端分离,后端写一堆接口:json格式)
  -抓包工具
  
  
# 11 自动化运维平台项目:
资产收集,
监控类,
一条命令自动安装:3,4  mysql5.7(ansiable),修改mysql配置文件

今日内容

1 css选择器和xpath选择器

# css选择器
#######
#1 css选择器
#######
# 重点

# Tag对象.select("css选择器")
#  #ID号
#  .类名
#   div>p:儿子 和div p:子子孙孙
#   找div下最后一个a标签 div a:last-child


# css选择器,xpath选择器会用了,它就是个通行证(所有的都可以不会,会粘贴就行)

# bs4:自己的选择器,css选择器
# lxml:css选择器,xpath选择器
# selenium:自己的选择器,css选择器,xpath选择器
# scrapy框架:自己的选择器,css选择器,xpath选择器
# #select('.article')



#该模块提供了select方法来支持css,详见官网:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id37
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title">
    <b>The Dormouse's story</b>
    Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">
        <span>Elsie</span>
    </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>;
    <div class='panel-1'>
        <ul class='list' id='list-1'>
            <li class='element'>Foo</li>
            <li class='element'>Bar</li>
            <li class='element'>Jay</li>
        </ul>
        <ul class='list list-small' id='list-2'>
            <li class='element'><h1 class='yyyy'>Foo</h1></li>
            <li class='element xxx'>Bar</li>
            <li class='element'>Jay</li>
        </ul>
    </div>
    and they lived at the bottom of a well.
</p>
<p class="story">...</p>
"""
from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml')


#1、CSS选择器(前端学的css选择)
print(soup.p.select('.sister'))
print(soup.select('.sister span'))

print(soup.select('#link1'))
print(soup.select('#link1 span'))

print(soup.select('#list-2 .element.xxx'))

print(soup.select('#list-2')[0].select('.element')) #可以一直select,但其实没必要,一条select就可以了

# 2、获取属性
print(soup.select('#list-2 h1')[0].attrs)

# 3、获取内容
print(soup.select('#list-2 h1')[0].get_text())
# xpath选择
# / 从根节点选取  /a   从根节点开始,往下找a标签(子)
# //从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置  //a 从根节点开始找a标签(子子孙孙中所有a)
# . 	选取当前节点。
# .. 	选取当前节点的父节点。
# @ 	选取属性。


########
# 2 xpath选择器
########


# XPath 是一门在 XML 文档中查找信息的语言

# xpath选择
# / 从根节点选取  /a   从根节点开始,往下找a标签(子)
# //从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置  //a 从根节点开始找a标签(子子孙孙中所有a)
# 取值 /text()
# 取属性 /@属性名


# //*[@id="auto-channel-lazyload-article"]/ul[1]
# //ul[1]
# //*[@id="focus-1"]/div[1]/ul/li[3]/h2

# #focus-1 > div.focusimg-pic > ul > li:nth-child(3) > h2
doc='''
<html>
 <head>
  <base href='http://example.com/' />
  <title>Example website</title>
 </head>
 <body>
  <div id='images'>
   <a href='image1.html' id="xxx">Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
   <h5>test</h5>
   <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'>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
html=etree.HTML(doc)  # 传字符串
# html=etree.parse('search.html',etree.HTMLParser())  # 文件

# 1 所有节点
# a=html.xpath('//*')
# 2 指定节点(结果为列表)
# a=html.xpath('//head')

# 3 子节点,子孙节点
# a=html.xpath('//div/a')

# a=html.xpath('//body/a') #无数据
# a=html.xpath('//body//a')

# 4 父节点
# a=html.xpath('//body//a[@href="image1.html"]/..')
# a=html.xpath('//body//a[@href="image1.html"]')
# a=html.xpath('//body//a[1]/..')
# 也可以这样
# a=html.xpath('//body//a[1]/parent::*')


# 5 属性匹配
# a=html.xpath('//body//a[@href="image1.html"]')

# 6 文本获取   标签后加:/text() ********重点
# a=html.xpath('//body//a[@href="image1.html"]/text()')
# a=html.xpath('//body//a/text()')

# 7 属性获取  标签后:/@href   ********重点
# a=html.xpath('//body//a/@href')
# # 注意从1 开始取(不是从0)
# a=html.xpath('//body//a[3]/@href')
# 8 属性多值匹配
#  a 标签有多个class类,直接匹配就不可以了,需要用contains
# a=html.xpath('//body//a[@class="li"]')
# a=html.xpath('//body//a[@href="image1.html"]')
# a=html.xpath('//body//a[contains(@class,"li")]')
# a=html.xpath('//body//a[contains(@class,"li")]/text()')
# a=html.xpath('//body//a[contains(@class,"li")]/@name')



# 9 多属性匹配 or 和 and (了解)
# a=html.xpath('//body//a[contains(@class,"li") or @name="items"]')
# a=html.xpath('//body//a[contains(@class,"li") and @name="items"]/text()')
# a=html.xpath('//body//a[contains(@class,"li")]/text()')


# 10 按序选择
# a=html.xpath('//a[2]/text()')
# a=html.xpath('//a[2]/@href')
# 取最后一个(了解)
# a=html.xpath('//a[last()]/@href')
# a=html.xpath('//a[last()]/text()')
# 位置小于3的
# a=html.xpath('//a[position()<3]/@href')
# a=html.xpath('//a[position()<3]/text()')
# 倒数第二个
# a=html.xpath('//a[last()-2]/@href')


# 11 节点轴选择
# ancestor:祖先节点
# 使用了* 获取所有祖先节点
# a=html.xpath('//a/ancestor::*')


# # 获取祖先节点中的div
# a=html.xpath('//a/ancestor::div')
# a=html.xpath('//a/ancestor::div/a[2]/text()')
# attribute:属性值
# a=html.xpath('//a[1]/attribute::*')
# a=html.xpath('//a[1]/@href')
# child:直接子节点
# a=html.xpath('//a[1]/child::*')
# a=html.xpath('//a[1]/img/@src')
# 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]')
# a=html.xpath('//a[1]/following-sibling::*[2]/@href')



print(a)

2 selenium的简单使用

#1  selenium最初是一个自动化测试工具,而爬虫中使用它主要是为了解决requests无法直接执行JavaScript代码的问题
 -可以操作浏览器(火狐,谷歌(建议你用谷歌),ie),模拟人的行为(人可以干啥,代码控制就可以干啥)
#2  测试开发和开发有什么区别


########
# 3 selenium的使用
#######
# pip3 install selenium

# 1 基本使用
from selenium import webdriver
# import time
# # 得到 一个谷歌浏览器对象
# # 代码不能直接操作浏览器,需要有一个浏览器驱动(配套的)
# # 下载谷歌浏览器驱动:http://npm.taobao.org/mirrors/chromedriver/
# # 谷歌浏览器驱动要跟谷歌版本对应
# # http://npm.taobao.org/mirrors/chromedriver/80.0.3987.106/   :80.0.3987.149(正式版本)
# # 指定一下驱动的位置(相对路径/绝对路径)
# bro=webdriver.Chrome(executable_path='./chromedriver')
#
# bro.get("https://www.baidu.com")
#
# # 页面内容
# # ret.text 相当于它,可以使用bs4解析数据,或者用selenium自带的解析器解析
# print(bro.page_source)
# time.sleep(5)
# bro.close()


3 selenium的高级用法

# import time
# # 2 常用用法(在输入框中输入美女,搜索)
# bro=webdriver.Chrome(executable_path='./chromedriver')
#
# bro.get("https://www.baidu.com")
# # 在输入框中输入美女(自带的解析器,查找输入框空间)
# # 1、find_element_by_id  # id找
# # 2、find_element_by_link_text   # a标签上的文字找
# # 3、find_element_by_partial_link_text # a标签上的文字模糊
# # 4、find_element_by_tag_name        # 根据标签名字找
# # 5、find_element_by_class_name      # 根据类名字找
# # 6、find_element_by_name            # name='xx' 根据name属性找
# # 7、find_element_by_css_selector    # css选择器找
# # 8、find_element_by_xpath           #xpath选择器找
#
# # //*[@id="kw"]
# # input_search=bro.find_element_by_xpath('//*[@id="kw"]')
# input_search=bro.find_element_by_css_selector('#kw')
#
# # 写文字
# input_search.send_keys("美女")
# # 查找搜索按钮
# enter=bro.find_element_by_id('su')
#
# time.sleep(3)
# # 点击按钮
# enter.click()
#
# time.sleep(5)
# bro.close()


# 3 小案例
# import time
# bro=webdriver.Chrome(executable_path='./chromedriver')
# bro.get("https://www.baidu.com")
#
# # 隐士等待(最多等待10s)
# # 只有控件没有加载出来,才会等,控件一旦加载出来,直接就取到
# bro.implicitly_wait(10)
#
# submit_button=bro.find_element_by_link_text('登录')
# submit_button.click()
#
# user_button=bro.find_element_by_id('TANGRAM__PSP_10__footerULoginBtn')
# user_button.click()
#
# user_input=bro.find_element_by_id('TANGRAM__PSP_10__userName')
# user_input.send_keys("ssssss@qq.com")
#
# pwd_input=bro.find_element_by_id('TANGRAM__PSP_10__password')
# pwd_input.send_keys("123456")
#
#
# submit_input=bro.find_element_by_id('TANGRAM__PSP_10__submit')
# submit_input.click()
#
# time.sleep(5)
# bro.close()


# 4 获取cookie
# 登陆之后,拿到cookie:就可以自己搭建cookie池(requests模块发请求,携带者cookie)
# # import time
# bro=webdriver.Chrome(executable_path='./chromedriver')
# bro.get("https://www.baidu.com")
# print(bro.get_cookies())
# bro.close()
#
# #搭建cookie池和代理池的作用是什么?封ip ,封账号(弄一堆小号,一堆cookie)

# 5 无界面浏览器(驱动谷歌,驱动其他浏览器)
# from selenium.webdriver.chrome.options import Options
# chrome_options = Options()
# chrome_options.add_argument('window-size=1920x3000') #指定浏览器分辨率
# chrome_options.add_argument('--disable-gpu') #谷歌文档提到需要加上这个属性来规避bug
# chrome_options.add_argument('--hide-scrollbars') #隐藏滚动条, 应对一些特殊页面
# chrome_options.add_argument('blink-settings=imagesEnabled=false') #不加载图片, 提升速度
# chrome_options.add_argument('--headless') #浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败
#
# bro=webdriver.Chrome(executable_path='./chromedriver',options=chrome_options)
# bro.get("https://www.baidu.com")
# print(bro.get_cookies())
# bro.close()


# 6 获取标签属性
# (重点:获取属性)
# print(tag.get_attribute('src'))
# print(tag.get_attribute('href'))
#(重点:获取文本)
# print(tag.text)
#
# #获取标签ID,位置,名称,大小(了解)
# print(tag.id)
# print(tag.location)
# print(tag.tag_name)
# print(tag.size)


# 7 显示等待和隐士等待
# 隐士等待(最多等待10s)
# 只有控件没有加载出来,才会等,控件一旦加载出来,直接就取到
# bro.implicitly_wait(10)
# 显示等待(每个控件,都要写等待),不要使用

# 8 元素交互操作 点击click,清空clear,输入文字send_keys


#9 执行js
import time
# bro=webdriver.Chrome(executable_path='./chromedriver')
#
# bro.get("https://www.cnblogs.com")
# # 执行js代码
# # bro.execute_script('alert(1)')
# # window.scrollTo(0,document.body.scrollHeight)
# bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
# time.sleep(5)
# bro.close()

# 10 模拟浏览器前进后推
# import time
# bro=webdriver.Chrome(executable_path='./chromedriver')
#
# bro.get("https://www.cnblogs.com")
# time.sleep(1)
# bro.get("https://www.baidu.com")
# time.sleep(1)
# bro.get("https://www.jd.com")
#
# #退到上一个
# bro.back()
# time.sleep(1)
# # 前进一下
# bro.forward()
#
# time.sleep(5)
# bro.close()

# 10 选项卡管理
# import time
# from selenium import webdriver
#
# browser=webdriver.Chrome(executable_path='./chromedriver')
# 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(2)
# browser.switch_to_window(browser.window_handles[0])
# browser.get('https://www.sina.com.cn')
# browser.close()

# 11 异常处理
# from selenium import webdriver
# from selenium.common.exceptions import TimeoutException,NoSuchElementException,NoSuchFrameException
#
# try:
#     browser=webdriver.Chrome(executable_path='./chromedriver')
#     browser.get('http://www.baidu.com')
#     browser.find_element_by_id("xxx")
#
# except Exception as e:
#     print(e)
# finally:
#     browser.close()

4 爬取京东商品信息

########
# 爬取京东商品信息
#######
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys
bro=webdriver.Chrome(executable_path='./chromedriver')



def get_goods(bro):
    # find_elements_by_class_name  找所有
    # find_element_by_class_name   找一个
    li_list=bro.find_elements_by_class_name('gl-item')
    # ul_list=bro.find_elements_by_css_selector('.gl-item')
    for li in li_list:
        url=li.find_element_by_css_selector('.p-img>a').get_attribute('href')
        url_img=li.find_element_by_css_selector('.p-img img').get_attribute("src")
        if not url_img:
            url_img='https:'+li.find_element_by_css_selector('.p-img img').get_attribute("data-lazy-img")
        price=li.find_element_by_css_selector('.p-price i').text
        name=li.find_element_by_css_selector('.p-name em').text
        commit=li.find_element_by_css_selector('.p-commit a').text

        print('''
        商品名字:%s
        商品价格:%s
        商品图片地址:%s
        商品地址:%s
        商品评论数:%s
        '''%(name,price,url,url_img,commit))

    #查找下一页按钮
    next=bro.find_element_by_partial_link_text('下一页')
    time.sleep(1)
    next.click()
    #继续抓取下一页
    get_goods(bro)

try:
    bro.get('https://www.jd.com')
    #隐士等待
    bro.implicitly_wait(10)
    input_search=bro.find_element_by_id('key')
    input_search.send_keys("精品内衣")
    #模拟键盘操作(模拟键盘敲回车)
    input_search.send_keys(Keys.ENTER)
    get_goods(bro)

except Exception as e:
    print(e)
finally:
    bro.close()

爬虫四:

昨日回顾

# 1 css选择器: #id号   .类名   div p  div>p
# 2 xpath选择: /  //  @src   /text()    .   ..
# 3 selenium:自动化测试用,解决不能执行js代码,操作浏览器,模拟人的行为(可见即可爬)
# 4 浏览器驱动(版本,型号对应)
# 5 send_keys,click,clear,键盘操作,执行js(下拉屏幕),获取cookie,打开选项卡,前进后退
# 6 爬取京东商品信息(css选择器和xpath选择器)

今日内容

1 scarpy框架的安装和启动

# 1 框架 不是 模块
# 2 号称爬虫界的django(你会发现,跟django很多地方一样)
# 3 安装
	-mac,linux平台:pip3 install scrapy
  -windows平台:pip3 install scrapy(大部分人可以)
  	- 如果失败:
      1、pip3 install wheel #安装后,便支持通过wheel文件安装软件,wheel文件官网:https://www.lfd.uci.edu/~gohlke/pythonlibs
      3、pip3 install lxml
      4、pip3 install pyopenssl
      5、下载并安装pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/
      6、下载twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
      7、执行pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd64.whl
      8、pip3 install scrapy
 # 4 在script文件夹下会有scrapy.exe可执行文件
		-创建scrapy项目:scrapy startproject 项目名   (django创建项目)
  	-创建爬虫:scrapy genspider 爬虫名 要爬取的网站地址   # 可以创建多个爬虫
    
 # 5 启动爬虫
			-scrapy crawl 爬虫名字
  		-scrapy crawl 爬虫名字 --nolog
 # 6 不在命令行下执行爬虫
	-在项目路径下创建一个main.py,右键执行即可
  	from scrapy.cmdline import execute
    # execute(['scrapy','crawl','chouti','--nolog'])
    execute(['scrapy','crawl','chouti'])

2 scrapy架构

image-20200410102350670

# 引擎(EGINE)(大总管)
引擎负责控制系统所有组件之间的数据流,并在某些动作发生时触发事件。有关详细信息,请参见上面的数据流部分。
# 调度器(SCHEDULER)
用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL的优先级队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
# 下载器(DOWLOADER)
用于下载网页内容, 并将网页内容返回给EGINE,下载器是建立在twisted这个高效的异步模型上的
# 爬虫(SPIDERS)
SPIDERS是开发人员自定义的类,用来解析responses,并且提取items,或者发送新的请求
# 项目管道(ITEM PIPLINES)
在items被提取后负责处理它们,主要包括清理、验证、持久化(比如存到数据库)等操作


# 两个中间件
-爬虫中间件
-下载中间件(用的最多,加头,加代理,加cookie,集成selenium)



3 配置文件,目录介绍

-crawl_chouti   # 项目名
  -crawl_chouti # 跟项目一个名,文件夹
    -spiders    # spiders:放着爬虫  genspider生成的爬虫,都放在这下面
    	-__init__.py
      -chouti.py # 抽屉爬虫
      -cnblogs.py # cnblogs 爬虫
    -items.py     # 对比django中的models.py文件 ,写一个个的模型类
    -middlewares.py  # 中间件(爬虫中间件,下载中间件),中间件写在这
    -pipelines.py   # 写持久化的地方(持久化到文件,mysql,redis,mongodb)
    -settings.py    # 配置文件
  -scrapy.cfg       # 不用关注,上线相关的
  
  
  
  
# 配置文件

ROBOTSTXT_OBEY = False   # 是否遵循爬虫协议,强行运行
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'    # 请求头中的ua
LOG_LEVEL='ERROR' # 这样配置,程序错误信息才会打印,
	#启动爬虫直接 scrapy crawl 爬虫名   就没有日志输出
  # scrapy crawl 爬虫名 --nolog



# 爬虫文件
class ChoutiSpider(scrapy.Spider):
    name = 'chouti'   # 爬虫名字
    allowed_domains = ['https://dig.chouti.com/']  # 允许爬取的域
    start_urls = ['https://dig.chouti.com/']   # 起始爬取的位置,爬虫一启动,会先向它发请求

    def parse(self, response):  # 解析,请求回来,自动执行parser,在这个方法中做解析
        print('---------------------------',response)

4 以抽屉为例,爬取数据并解析

# 1 解析,可以使用bs4解析
from bs4 import BeautifulSoup
soup=BeautifulSoup(response.text,'lxml')
soup.find_all()
# 2 内置的解析器
# response.css  
# response.xpath

# 解析 
  # 所有用css或者xpath选择出来的都放在列表中
  # 取第一个:extract_first()
  # 取出所有extract()
  # css选择器取文本和属性:
    # .link-title::text
    # .link-title::attr(href)
  # xpath选择器取文本和属性
    # .//a[contains(@class,"link-title")/text()]
    #.//a[contains(@class,"link-title")/@href]

5 持久化

# 方式一(讲完就忘了)
	-1 parser解析函数,return 列表,列表套字典
  -2 scrapy crawl chouti -o aa.json   (支持:('json', 'jsonlines', 'jl', 'csv', 'xml', 'marshal', 'pickle')
# 方式二 pipline的方式(管道)
   -1 在items.py中创建模型类
   -2 在爬虫中chouti.py,引入,把解析的数据放到item对象中(要用中括号)
   -3 yield item对象
   -4 配置文件配置管道
       ITEM_PIPELINES = {
        # 数字表示优先级(数字越小,优先级越大)
       'crawl_chouti.pipelines.CrawlChoutiPipeline': 300,
       'crawl_chouti.pipelines.CrawlChoutiRedisPipeline': 301,
    	}
  -5 pipline.py中写持久化的类
        	-spider_open
          -spider_close
          -process_item(在这写保存到哪)
                                       
                                       	

6 动作链,自动登录12306

# 1 生成一个动作练对象
action=ActionChains(bro)
# 2 点击并夯住某个控件
action.click_and_hold(div)
# 3 移动(三种方式)
# action.move_by_offset() # 通过坐标
# action.move_to_element() # 到另一个标签
# action.move_to_element_with_offset() # 到另一个标签,再偏移一部分

# 4 真正的移动
action.perform()

# 5 释放控件(松开鼠标)
action.release()


爬虫五:

昨日回顾

# 有没有面试机会,取决于你的简历(简历,是可以润色的)3年工作经验,激进一些,不要那么保守
	# 属性python,熟悉oop,熟悉pep8规范
  # 熟悉django,flask
  # 了解redis,了解linux,能部署项目
  # 了解celery,能简单的集成到django中
# 能不能入职,取决于你的面试表现

# 1 scrapy 安装:pip3 install scray
# 2 scrapy startproject 项目名字
# 3 scrapy genspider 爬虫名字 地址
# 4 目录结构
# 5 架构:5大组件,2大中间件
# 6 以抽屉为例:css选择器和xpath选择器
		-extract()
  	-extract_first()
    -css文本:     ::text
    -css属性:    ::attr(属性名)
    -xpath文本:    /text()
    -xpath属性:    /@属性名
# 7 持久化的两种方案
	-用命令 scrapy crawl 爬虫 -o 文件名.json   (parser:必须return 列表)
  -通过管道方式
  	-1 写一个模型类
    -2 爬虫的parser函数中,把解析出的数据,放到模型类对象中 yield 对象
    -3 在setting中配置(数字越小,优先级越高)
    -4 piplins中写一个类, open_spider  close_spider process_item(是否:return)
    
 # 8 动作链(了解)    自动登录12306(登录不是你的目的)cookie:能自动登录就登陆,不能就手动登陆
 		-获取到cookie:redis(搭建cookie池)
  	-只是定时任务(apscheduler)
    -celery:定时任务和异步任务
    -windows 不支持(明明白白写的,不支持windows)

    

今日内容

1 全站爬取cnblogs

# 1 scrapy startproject cnblogs_crawl
# 2 scrapy genspider cnblogs www.cnblogs.com

2 scarpy请求传参

# 1 放 :yield Request(url,callback=self.parser_detail,meta={'item':item})
# 2 取:response.meta.get('item')

3 提高爬取效率

- 在配置文件中进行相关的配置即可:(默认还有一套setting)
#1 增加并发:
默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。
#2 提高日志级别:
在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:LOG_LEVEL = ‘INFO’
# 3 禁止cookie:
如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:COOKIES_ENABLED = False
# 4禁止重试:
对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:RETRY_ENABLED = False
# 5 减少下载超时:
如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:DOWNLOAD_TIMEOUT = 10 超时时间为10s

4 下载中间件

# 2大中间件:下载中间件,爬虫中间件

# 1 写在middlewares.py中(名字随便命名)
# 2 配置生效()
		SPIDER_MIDDLEWARES = {
   'cnblogs_crawl.middlewares.CnblogsCrawlSpiderMiddleware': 543,
}
	DOWNLOADER_MIDDLEWARES = {
   'cnblogs_crawl.middlewares.CnblogsCrawlDownloaderMiddleware': 543,
}
  
# 2 下载中间件
	-process_request:(请求去,走)
  			# - return None: 继续处理当次请求,进入下一个中间件
        # - return Response: 当次请求结束,把Response丢给引擎处理(可以自己爬,包装成Response)
        # - return Request : 相当于把Request重新给了引擎,引擎再去做调度
        # - 抛异常:执行process_exception
  -process_response:(请求回来,走)
  		  # - return a Response object :继续处理当次Response,继续走后续的中间件
        # - return a Request object:重新给引擎做调度
        # - or raise IgnoreRequest :process_exception
  -process_exception:(出异常,走)
  		   # - return None: continue processing this exception
        # - return a Response object: stops process_exception() chain  :停止异常处理链,给引擎(给爬虫)
        # - return a Request object: stops process_exception() chain :停止异常处理链,给引擎(重新调度)

5 集成selenium

# 在爬虫已启动,就打开一个chrom浏览器,以后都用这一个浏览器来爬数据

# 1 在爬虫中创建bro对象
	bro = webdriver.Chrome(executable_path='/Users/liuqingzheng/Desktop/crawl/cnblogs_crawl/cnblogs_crawl/chromedriver')

# 2 中间件中使用:
  spider.bro.get(request.url)
  text=spider.bro.page_source
  response=HtmlResponse(url=request.url,status=200,body=text.encode('utf-8'))
  return response
# 3 关闭,在爬虫中
    def close(self, reason):
        self.bro.close()


6 fake-useragent

# 请求头中的user-agent
list=['','']

# pip3 install fake-useragent

# https://github.com/hellysmile/fake-useragent
from fake_useragent import UserAgent
ua=UserAgent(verify_ssl=False)
print(ua.random)

7 去重源码分析

# 去重源码分析
# from scrapy.core.scheduler import Scheduler
# Scheduler下:def enqueue_request(self, request)方法判断是否去重
	if not request.dont_filter and self.df.request_seen(request):
   	Requests对象,RFPDupeFilter对象
# 如果要自己写一个去重类
	-写一个类,继承BaseDupeFilter类
  -重写def request_seen(self, request):
  -在setting中配置:DUPEFILTER_CLASS = '项目名.dup.UrlFilter'

# scrapy起始爬取的地址
    def start_requests(self):
        for url in self.start_urls:
            yield Request(url)
          
          
          
          
-增量爬取(100链接,150个链接)
  -已经爬过的,放到某个位置(mysql,redis中:集合)
  -如果用默认的,爬过的地址,放在内存中,只要项目一重启,就没了,它也不知道我爬过那个了,所以要自己重写去重方案
-你写的去重方案,占得内存空间更小
	-bitmap方案
	-BloomFilter布隆过滤器
  
  
  
from scrapy.http import Request
from scrapy.utils.request import request_fingerprint

# 这种网址是一个
requests1=Request(url='https://www.baidu.com?name=lqz&age=19')
requests2=Request(url='https://www.baidu.com?age=18&name=lqz')

ret1=request_fingerprint(requests1)
ret2=request_fingerprint(requests2)
print(ret1)
print(ret2)



# bitmap去重  一个小格表示一个连接地址 32个连接,一个比特位来存一个地址
# https://www.baidu.com?age=18&name=lqz ---》44
# https://www.baidu.com?age=19&name=lqz ---》89
# c2c73dfccf73bf175b903c82b06a31bc7831b545假设它占4个bytes,4*8=32个比特位
# 存一个地址,占32个比特位
# 10个地址,占320个比特位
#计算机计量单位
# 比特位:只能存0和1
# 8个比特位是一个bytes
# 1024bytes=1kb
# 1024kb=1m
# 1024m=1g

# 布隆过滤器:原理和python中如何使用
    def request_seen(self, request):
        # 把request对象传入request_fingerprint得到一个值:aefasdfeasd
        # 把request对象,唯一生成一个字符串
        fp = self.request_fingerprint(request)
        #判断fp,是否在集合中,在集合中,表示已经爬过,return True,他就不会再爬了
        if fp in self.fingerprints:
            return True
        # 如果不在集合中,放到集合中
        self.fingerprints.add(fp)
        if self.file:
            self.file.write(fp + os.linesep)

8 分布式爬虫

# 1 安装pip3 install scrapy-redis

# 源码部分,不到1000行,
    
# 1 原来的爬虫继承
from scrapy_redis.spiders import RedisSpider
class CnblogsSpider(RedisSpider):
  	#start_urls = ['http://www.cnblogs.com/']
    redis_key = 'myspider:start_urls'
    
# 2 在setting中配置
  SCHEDULER = "scrapy_redis.scheduler.Scheduler"
  DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
  ITEM_PIPELINES = {
     'scrapy_redis.pipelines.RedisPipeline': 300
  }
# 3 多台机器上启动scrapy
# 4 向reids中发送起始url
lpush myspider:start_urls https://www.cnblogs.com



补充

# 编译型语言和解释型语言
# python,js,php 解释型: 一定要有个解释器 (全都夸平台,在不同平台装不通平台的解释器即可)
# 编译型语言:c,c++   java(有人说是编译型,有人说是解释型)
	-java:jdk,jre,jvm(三个分别是啥)
  	-jdk:java开发环境(开发人员要装)
    -jre:java运行环境(要运行java程序,必须装)
    -jvm:java虚拟机,所有的java程序必须运行在虚拟机之上
    -java对外发布:跨平台,一处编码,处处运行(1990年)
    -java编译----》字节码文件(.class文件)----》字节码文件在jvm上运行---》在不同平台装不通java虚拟---》实现了跨平台
    -java:1.5---》古老   1.6 1.7 ---》java 8(用的还比较多)---》java9 ---》java13
    
  -c语言:写完了,想在windwos下运行----》跑到windows机器下编译成可执行文件
  					   -想在linux下运行----》跑到linux机器下编译成可执行文件
   			-linux上装python环境(源码安装,make,make install)
  -go编译型:跨平台编译(在windows上可以编译出linux下可执行文件)---》2009年--》微服务
  	-所有代码都编译成一个可执行文件(web项目---》编译之后---》可执行文件---》丢到服务器就能执行,不需要安装任何依赖)
	-java要运行---》最低最低要跑在java虚拟机之上(光jvm要跑起来,就占好几百m内存)---》
	-安卓手机app--java开发的---》你的安卓手机在上面跑了个jvm
  
  -go:就是个可执行文件(go的性能比java高,他俩不相上下),阿里:自己写了jvm
  -安卓:谷歌,---->当时那个年代,java程序员多---》java可以快速转过去---》
  -谷歌:Kotlin:---》用来取代java---》写安卓---》在国际上排名比go高
  -同年ios/mac软件:object-c-----》swift(苹果的一个工程师,没事的时候,写的一个语言)---》过了没几年,跳槽去了facebook----》
  
  -java:sun公司出的,后来被甲骨文收购了,开始恶心人---》把java做成收费---》一门收费
  -c#:微软的:一开始收费,比java要好,没人用,免费,开源了,也没人用
  
  -java se  java ee  java me
  
  -python写的代码,用打包工具,打包成exe----》把代码和解释器统统打包到exe中了
  -垃圾回收机制:挺高端
  


# 1 代码发布系统 +cmdb+监控+日志---》devops平台、自动化运维平台
# 2 go挺高级(并发)前端,mysql,redis,mongodb,es    缺了个go的web框架,orm
	-beego:中国人写的(跟django很像。orm,中间件。。。。。)https://beego.me/docs/intro/
  -gin:老外写的(flask,没有orm ),gorm   https://github.com/gin-gonic/gin
  -Iris:


posted @ 2020-06-27 16:04  晴天sky  阅读(201)  评论(0编辑  收藏  举报
左边日期 搜索的制定样式