爬虫简介
爬虫初始深入
爬虫在使用场景中的分类
- 通用爬虫:
- 抓取系统重要组成部分。抓取的是一整张页面数据
- 聚焦爬虫:
- 是建立在通用爬虫的基础上。抓取的是页面中特定的局部内容。
- 增量式爬虫
- 监测网站中数据更新的情况。只会抓取网站中最新更新出来的数据。
- 反爬机制
-
- 可以通过制定相应的策略或技术手段防止爬虫进行爬取。
- 反反爬策略
-
- 可以通过制定相关策略或技术手段破解反爬机制从而可以获取门户网站中相关的数据。
反爬机制:robots.txt协议
君子协议,规定了网站中哪些数据可以被爬虫爬取,哪些不可以。
HTTP&HTTPS
超文本传输协议:服务器和客户端进行数据交互的一种形式
常用请求头信息
- User-Agent:请求载体的身份标识
- Connection:请求完毕后,是断开连接还是保持连接
常用响应头信息
- Content-Type: 服务器响应回客户端的数据类型。
https协议
- 安全的超文本传输协议
加密方式
- 对称密钥加密:将密文和密钥一起发送
- 非对称密钥加密:公开密钥加密,私有密钥解密。(客户端拿到的公钥可能被篡改)
- 证书密钥加密(https):加入证】书认证机构
requests模块基础
以json文件保存到本地
file = open('./huanzhuanpin.json','w',encoding='utf-8')
json.dump(all_data,fp=file,ensure_ascii=False)
使用xpath
在使用xpath时,如果首先提取出所有的某个xpath,然后从当前xpath下继续找符合xpath的项目路径,必须在前面加. dot 的!!!
div_list = response.xpath('//*[@id="i_cecream"]/div[2]/main/div[2]/div/div[1]/div')
for div in div_list:
author = div.xpath('.//div[@class="bili-video-card__info--right"]//a/span[@class="bili-video-card__info--author"]/text()').extract() # xpath要从上一层的xpath开始找,必须在最前面加个. !!
#author = div.xpath('不对这里没有点//div[@class="bili-video-card__info--right"]//a/span[@class="bili-video-card__info--author"]/text()').extract() # xpath要从上一层的xpath开始找,必须在最前面加个. !!
使用bs4 beautifulSoup
bs4进行数据解析
- 数据解析的原理:
- 1.标签定位
- 2.提取标签、标签属性中存储的数据值
- bs4数据解析的原理:
- 1.实例化一个BeautifulSoup对象,并且将页面源码数据加载到该对象中
- 2.通过调用BeautifulSoup对象中相关的属性或者方法进行标签定位和数据提取
- 环境安装:
- pip install bs4
- pip install lxml
- 如何实例化BeautifulSoup对象:
- from bs4 import BeautifulSoup
- 对象的实例化:
- 1.将本地的html文档中的数据加载到该对象中
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
- 2.将互联网上获取的页面源码加载到该对象中
page_text = response.text
soup = BeatifulSoup(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'):>表示的是一个层级
- oup.select('.tang > ul a'):空格表示的多个层级
- 获取标签之间的文本数据:
- soup.a.text/string/get_text()
- text/get_text():可以获取某一个标签中所有的文本内容
- string:只可以获取该标签下面直系的文本内容
- 获取标签中属性值:
- soup.a['href']
# bs4 解析基础
from bs4 import BeautifulSoup
if __name__ == "__main__":
#将本地的html文档中的数据加载到该对象中
fp = open('./test.html','r',encoding='utf-8')
soup = BeautifulSoup(fp,'lxml')
# print(soup)
# print(soup.a) #soup.tagName 返回的是html中第一次出现的tagName标签
# print(soup.div)
#find('tagName'):等同于soup.div
# print(soup.find('div')) #print(soup.div)
# print(soup.find('div',class_='song').string)
# print(soup.find_all('a'))
# print(soup.select('.tang'))
print(soup.select('.tang > ul a')[0]['href'])
cd ../
是返回上一层目录
创建目录
if not os.path.exists('./美女'):
os.makedirs('./美女')
编码解码
url = 'http://pic.netbian.com/4kmeinv/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'
}
response = requests.get(url, headers=headers)
code = requests.get(url).encoding
print(code) # ISO-8859-1网页的编码格式
# 所以需要将ISO-8859-1解码成utf-8才可以
page_text = requests.get(url, headers=headers).text
page_text = page_text.encode('ISO-8859-1').decode('gbk', 'ignore')
print(page_text)
with open('./img.html', 'w', encoding='utf-8') as fp:
fp.write(page_text)
string.strip() 表示去掉空格
xpath解析:etree
xpath解析:最常用且最便捷高效的一种解析方式。通用性。
- xpath解析原理:
- 1.实例化一个etree的对象,且需要将被解析的页面源码数据加载到该对象中。
- 2.调用etree对象中的xpath方法结合着xpath表达式实现标签的定位和内容的捕获。
- 环境的安装:
- pip install lxml
- 如何实例化一个etree对象:from lxml import etree
- 1.将本地的html文档中的源码数据加载到etree对象中:
etree.parse(filePath)
- 2.可以将从互联网上获取的源码数据加载到该对象中
etree.HTML('page_text')
- xpath('xpath表达式')
- xpath表达式:
- /:表示的是从根节点开始定位。表示的是一个层级。
- //:表示的是多个层级。可以表示从任意位置开始定位。
- 属性定位://div[@class='song'] tag[@attrName="attrValue"]
- 索引定位://div[@class="song"]/p[3] 索引是从1开始的。
- 取文本:
- /text() 获取的是标签中直系的文本内容
- //text() 标签中非直系的文本内容(所有的文本内容)
- 取属性:
/@attrName ==>img/src
- eg:house_list = tree.xpath('//h4/a/span/text()')
验证码识别
# 古诗文网验证码识别
import requests
from lxml import etree
from chaojiying import Chaojiying_Client
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) CXXXXXXXXXXXXXX 21 Safari/537.36'
}
url = 'https://so.gushiwen.org/user/login.aspx?from=http://so.gushiwen.org/user/collect.aspx'
s = requests.session()
response = s.get(url, headers=headers)
page_text = response.text
tree = etree.HTML(page_text)
img_url = 'https://so.gushiwen.org' + tree.xpath('//*[@id="imgCode"]/@src')[0]
img = s.get(url=img_url, headers=headers).content
print(img_url)
with open('./yzm.jpg', 'wb') as fp:
fp.write(img)
# 使用超级鹰得到验证码
chaojiying = Chaojiying_Client('XXX', 'XXXX', '952676')
dic = chaojiying.PostPic(img, 1004)
verify_code = dic["pic_str"]
login_url = 'https://so.gushiwen.cn/user/login.aspx?from=http%3a%2f%2fso.gushiwen.cn%2fuser%2fcollect.aspx'
data = {
'__VIEWSTATE': 'SCcutwzLBUaJBXYsxubHJdILMBPYSbG/xn9ZgE+OFIUQi5BtHvFAG6vioZUJs9162jQMa6jgqbdYr585FqTzgOR0DLz+L61CuB0peIp7AQwD52toTxIIkgwlujWYQwA2OREmNGx1pc2hgJN9eO5zUrMu8FI=__VIEWSTATEGENERATOR: C93BE1AE',
'from': 'http://so.gushiwen.cn/user/collect.aspx',
'email': '1457154996@qq.com',
'pwd': 'liu1457154996',
'code': verify_code,
'denglu': '登录'
}
login_html = s.post(url=login_url, data=data, headers=headers)
login_text = login_html.text
print(verify_code)
print(login_text)
print(login_html.status_code)
with open('./login.html', 'w', encoding='utf-8') as fp:
fp.write(login_text)
代理IP
使用上了,但是timeout了。
import random
from time import sleep
import requests
from lxml import etree
# 使用快代理获取的ip https://www.kuaidaili.com/free/inha/4/
url = 'http://www.baidu.com/s?wd=ip'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
}
# 代理IP
PROXY_IP = ['49.82.123.7',
'115.197.163.107',
'113.229.60.120',
'112.194.164.173',
'221.201.203.153',
'110.89.123.26']
for i in range(5):
response = requests.get(url=url, headers=headers, proxies={"http": "http://" + random.choice(PROXY_IP)})
print(response.status_code)
print(response.request.url)
page_text = response.text
page_text = page_text.encode('utf-8').decode('gbk', 'ignore')
with open('./ip'+str(i)+'.html', 'w') as fp:
fp.write(page_text)
tree = etree.HTML(page_text)
ip = tree.xpath('/html/body/div[3]/div[5]/div[1]/div[3]/div[2]/div/div[1]/div[3]/div[1]/div/div[3]/span[2]/text()')
# ip = ''.join(ip).strip()
print("当前ip为", ip)
sleep(4)
"""
# 代理IP地址和端口,替换为您自己的代理IP信息
PROXY_PORT = '1'
# 使用代理IP的中间件
HTTP_PROXY = f'http://{random.choice(PROXY_IP)}:{PROXY_PORT}'
HTTPS_PROXY = f'https://{random.choice(PROXY_IP)}:{PROXY_PORT}'
"""
多线程下载pear_video
import json
import os.path
import random
import time
from multiprocessing.dummy import Pool
import requests
from lxml import etree
url = 'https://www.pearvideo.com/category_1'
headers = {
'User-Agent': 自己写
}
page_text = requests.get(url=url, headers=headers).text
tree = etree.HTML(page_text)
# with open('./lishipin.html', 'w', encoding='utf-8') as fp:
# fp.write(page_text)
# 获取video_name , video_url
video_list = tree.xpath('//*[@id="listvideoListUl"]//div[@class="vervideo-bd"]/a/@href')
video_name_list = tree.xpath('//div[@class="category-top"]//div[@class="vervideo-title"]/text()') #
video_list = ["https://www.pearvideo.com/" + video for video in video_list]
print(video_list)
print(video_name_list)
# 获取视频的真正下载链接
video_download_url = []
for i in range(len(video_list)):
contID = video_list[i].split('_')[1]
mrd = random.random()
video_url = f"https://www.pearvideo.com/videoStatus.jsp?contId={contID}&mrd=" + str(mrd) # 实测没有mrd相关信息也可以解析。
headers_video = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
"Referer": f"https://www.pearvideo.com/video_{contID}"
}
video_response = requests.get(video_url, headers=headers_video)
print(video_response.text)
# 将文件写入磁盘
fp = open(f'./{contID}.json', 'w', encoding='utf-8')
json.dump(video_response.json(), fp, ensure_ascii=False)
# 将fake的url转为真正的url
systemTime = video_response.json()['systemTime']
srcUrl = video_response.json()['videoInfo']['videos']['srcUrl']
srcUrl = srcUrl.replace(systemTime, f"cont-{contID}")
video_download_url.append(srcUrl)
print(video_download_url)
# 使用多线程进行下载
if not os.path.exists('../6章:高性能爬虫/梨视频'):
os.makedirs('../6章:高性能爬虫/梨视频')
i=0
def download_video(video):
global i # 在函数内修改全局变量:在函数内声明global变量
with open(f'./梨视频/{video_name_list[i]}.mp4', 'wb') as fp:
fp.write(requests.get(video).content)
print(video_name_list[i], "下载成功")
i+=1
# 单线程下载
start_time = time.time()
for video in video_download_url:
download_video(video)
end_time = time.time()
print("单线程下载时间:", end_time - start_time)
# 多线程下载
pool = Pool(len(video_list)) # 获取大小为视频个数的线程池
start_time = time.time()
i=0
pool.map(download_video, video_download_url)
end_time = time.time()
print("多线程下载时间:", end_time - start_time)
7章selenium
可以得到动态加载出的数据。
selenium 基础用法
from selenium import webdriver
from lxml import etree
from time import sleep
from selenium.webdriver.chrome.service import Service
service = Service(executable_path='./chromedriver.exe')
options = webdriver.ChromeOptions()
#实例化一个浏览器对象(传入浏览器的驱动成)
bro = webdriver.Chrome(service=service, options=options)
#让浏览器发起一个指定url对应请求
bro.get('http://125.35.6.84:81/xk/')
#page_source获取浏览器当前页面的页面源码数据
page_text = bro.page_source
#解析企业名称
tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@id="gzlist"]/li')
for li in li_list:
name = li.xpath('./dl/@title')[0]
print(name)
sleep(5)
bro.quit()
selenium其他自动化操作
import time
from selenium import webdriver
from time import sleep
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
service = Service(executable_path='./chromedriver.exe')
browser = webdriver.Chrome(service=service)
browser.get('https://www.taobao.com/')
# 标签定位
search_input = browser.find_element(By.ID, value='q') # 通过id为q找到搜索框
# 标签交互
search_input.send_keys('iphone') #发送字符串
# 执行一组js程序
browser.execute_script('window.scrollTo(0,document.body.scrollHeight)')
sleep(2)
# 点击搜索按钮
btn = browser.find_element(By.CSS_SELECTOR, '.btn-search') #CSS_SELECTOR用法: .classname:选择具有指定类名的元素。
btn.click() # 点击按钮
sleep(5)
browser.get('https://www.baidu.com')
sleep(2)
# 回退
browser.back()
time.sleep(2)
# 前进
browser.forward()
sleep(2)
# 退出浏览器
browser.quit()
"""
By有的函数:
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
"""
动作链和iframe框架
from selenium import webdriver
from time import sleep
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
# 浏览器驱动
service = Service(executable_path='./chromedriver.exe')
browser = webdriver.Chrome(service=service)
browser.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
# 如果定位的标签是存在于iframe标签之中的,则必须通过如下操作进行标签定位
browser.switch_to.frame('iframeResult') # 切换浏览器标签定位的作用域 参数为iframe标签的id
div = browser.find_element(By.ID, 'draggable') # 通过ID找对应ID非常方便
# 动作链
action = ActionChains(browser)
# 点击长按指定的标签
action.click_and_hold(div)
for i in range(5):
# perform()立即执行动作链操作
# move_by_offset(x, y): x:水平方向 y:垂直方向
action.move_by_offset(18, 0).perform()
sleep(.5)
# 释放动作链
action.release().perform()
sleep(5)
browser.quit()