一、反爬策略
面试:必问一个点。----间接反映你的反爬能力。
1、通过user-agent来判断是否是爬虫.
解决办法:封装user-agent。
准备user-agent池
[
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
"Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
"Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
"Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
"Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
"Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
"Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",
"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",
"Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52",
]
2、封ip:是网站针对爬虫最终策略。
解决办法:使用代理ip—代理池项目
3、通过请求的频率来限制爬取。
解决办法:
(1)设置请求头频率限制。time.sleep(0.1-0.9)
(2)减少请求次数:能在列表页获取,就不再详情页。但是要记得保存详情页url。
能一次获取,就多次获取。(ajax请求。limit:50)
4、验证码:破解验证码
5、数据不是直接渲染到html页面中,而是通过js异步获取数据。
解决办法:使用内置浏览器引擎的爬虫(selenium+chrome/phantomjs)
二、selenium
数据不是直接渲染到html页面中,而是通过js异步获取数据,这种网页破解的核心就是执行js代码,执行之后数据就会在页面中显示出来。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tvFKIqRW-1633970219298)(assets/1604716100097.png)]
在开发者工具中Elments元素里面的html页面的内容和请求得到html页面内容有时候是不一样的。
找xpath元素的时候如果按照element标签属性找发现没找到,这时候应该查看请求返回真实响应的页面中到底有没有这个属性。
(一)什么是selenium?
Selenium是一个Web的自动化测试工具,可以控制浏览器自动完成某些操作,但是selenium不带浏览器,selenium相当于一个浏览器的驱动程序。
内置浏览器引擎的爬虫组合:
可视化组合:selenium+chrome
无界面组合:selenium+phantomjs
(二)什么是phantomjs?
PhantomJS是一个基于Webkit的“无界面”(headless)浏览器,它会把网站加载到内存并执行页面上的JavaScript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效。
但是phantomjs好久未更新,现在使用起来容易被网站检测出来,进而屏蔽phantomjs。
(三)安装
1、安装selenium
pip install selenium==2.48.0
2、安装chromedriver
(1)下载:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DpmKrVam-1633970219300)(assets/1604716674924.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KfZyCNZa-1633970219302)(assets/1604716860932.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h79ANigZ-1633970219304)(assets/1604716881702.png)]
将下载好的exe工具:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RGBg0Yjq-1633970219305)(assets/1604717027402.png)]
放到pip工具包下面:D:\python\Scripts—目的:这个包肯定是配置过环境变量。
(2)测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U2KhaNOM-1633970219307)(assets/1604717133395.png)]
3、phantomjs安装
(1)下载:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R6oajUMc-1633970219308)(assets/1604717224041.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rPFi3TKD-1633970219310)(assets/1604717233326.png)]
(2)安装:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H2x9jEBg-1633970219312)(assets/1604717254843.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4gjRpMcY-1633970219313)(assets/1604717275350.png)]
将上述exe工具放到和chromedirver相同的位置即可。
(3)测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-enpd6DnC-1633970219314)(assets/1604717324671.png)]
(四)selenium的基本操作
文档:selenuim常用方法总结.note
链接:http://note.youdao.com/noteshare?id=0142a95cf23fadbaea95809ccb5674b2&sub=02896A50836E4995997A821419D9A063
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hrracdul-1633970219315)(assets/1604720336384.png)]
#导包
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
#1、创建浏览器
#selnium支持各种主流浏览器
driver = webdriver.Chrome()#创建一个可视化的chrome浏览器
# driver = webdriver.PhantomJS()
# driver = webdriver.Firefox()
# driver = webdriver.Safari()
# driver = webdriver.Ie()
#2、请求url
driver.get('https://www.baidu.com/')
input_lable = driver.find_element_by_id('kw')
print(input_lable)#WebElement对象
#WebElement对象相当于页面中的一个一个标签
#WebElement对象所能完成的操作和标签的功能是一致的。
#input-->输入
input_lable.send_keys('python基础大全')
#btn--按钮---点击 click()
#a----->click()
#普通标签:获取属性
print(input_lable.get_attribute('class'))
#找webelement元素的方法有三个:
#通过id选择
# driver.find_element_by_id()
#通过xpath选择
# driver.find_element_by_xpath()
# driver.find_elements_by_xpath()
#通过css选择器选择
# driver.find_element_by_css_selector()
# driver.find_elements_by_css_selector()
btn_submit = driver.find_element_by_xpath('//*[@id="su"]')
btn_submit.click()
#程序的运行必chrome浏览器页面反映要快很多。
#一定要记住等待是非常重要的。
time.sleep(2)
#完成input内容的清空功能
# input_lable.send_keys(Keys.CONTROL,'a')
# input_lable.send_keys(Keys.CONTROL,'x')
# input_lable.send_keys('流畅的python')
# btn_submit.click()
#最大化
# driver.maximize_window()
# #截屏
# driver.save_screenshot('page.png')
# #退出浏览器
# driver.quit()
# #关闭选项卡
# driver.close()
print(input_lable.location)#{'x': 142, 'y': 17}
print(input_lable.size)#{'x': 142, 'y': 17}
(五)豆瓣图书项目
import time
from lxml import etree
from selenium import webdriver
#定位器
from selenium.webdriver.common.by import By
#条件
from selenium.webdriver.support import expected_conditions as EC
#显示等待的对象
from selenium.webdriver.support.wait import WebDriverWait
def get_content_by_selenium(url):
'''
通过selenium获取页面数据
:param url:
:return:
'''
# #1、创建驱动
# driver = webdriver.Chrome()
#2、请求url
driver.get(url)
#3、等待---非常重要
#问题:1秒合不合理?
#第一种:强制等待
#缺点:时间不好确定,容易造成程序性能的损耗。
# time.sleep(1)
#第二种:隐式等待:等到页面加载完成,不再转圈圈为止。
#20:最大等待时长
# driver.implicitly_wait(20)
#弊端:
#(1)等待页面所有的静态文件以及js全部加载完成。--可能这些内容比较消耗时间。不能等待页面特定元素出现为止。
#(2)遇到页面异步加载的,不能使用隐式等待。
#第三种等待方式:显示等待:可以等待【页面特定元素】满足【特定的条件为止】。
#找元素的方法可以使用定位器:是一个元组
#(1)创建一个显示等待对象
wait = WebDriverWait(driver,20)
#presence_of_element_located:等到元素出现为止--单个元素
#presence_of_all_elements_located:多个元素
result = wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@id="root"]/div/div[2]/div/div/div[position()>1]')))
# print(result)
#4、获取页面内容
#page_source:页面加载完所有信息后显示的内容
html_str = driver.page_source
return etree.HTML(html_str)
def parse_page(tree):
'''
提取页面数据
:param tree:
:return:
'''
div_list = tree.xpath('//div[@id="root"]/div/div[2]/div/div/div[position()>1]')
print(div_list)
for div in div_list:
# print(div)
try:
# 书名
book_title = div.xpath('.//div[@class="title"]/a/text()')[0]
book_url = div.xpath('.//div[@class="title"]/a/@href')[0]
# print(book_title)
infos = div.xpath('.//div[@class="meta abstract"]/text()')[0].split('/')
if len(infos)>=4:
book_author = infos[0]
book_price = infos[-1]
book_publish = infos[-3]
book_pub_date = infos[-2]
item = {}
item['book_title'] = book_title
item['book_url'] = book_url
item['book_author'] = book_author
item['book_price'] = book_price
item['book_publish'] = book_publish
item['book_pub_date'] = book_pub_date
print(item)
except Exception:
pass
def main():
#1、确定url
base_url = 'https://book.douban.com/subject_search?search_text=python&cat=1001&start=%s'
#2、分页
# for i in range(30):
for i in range(5):
tree = get_content_by_selenium(base_url %(i*15))
#3提取页面数据
parse_page(tree)
if __name__ == '__main__':
# 1、创建驱动--放到全局变量中
driver = webdriver.Chrome()
main()
三、ajax
AJAX—异步的 JavaScript 和 XML
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
(一)ajax原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vBduGMqW-1633970219316)(assets/ajax原理.png)]
(二)ajax分析流程
案例:豆瓣电影
第一步:找接口
通过js事件来确定接口。
确定了页面数据变化的事件----滑动。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gFI9fSYW-1633970219317)(assets/1604737986510.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9QWo5KTW-1633970219318)(assets/1604738008804.png)]
第二步:定接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j13Zz6CF-1633970219319)(assets/1604738055565.png)]
第三步:分析接口
分析的目标是:不管是post请求还是get请求,参数都是分析的目标
如果参数加密了----变成js加密。—非常难。
一般分析参数方法就是:对比。对比的目的:找到变化参数,这些变化的参数就是分析的重点。
第四步:写代码
思路:先获取参数,在发送ajax请求。
豆瓣电影:
(1)从首页获取type值
(2)发送ajax请求。
import json
import requests,re
from lxml import etree
def get_content(url,headers ):
response = requests.get(url,headers=headers)
return response.text
def get_type_id(type_urls):
'''
获取type_id
:param type_urls:
:return:
'''
type_ids = []
#/typerank?type_name=剧情&type=11&interval_id=100:90&action=
for type_ in type_urls:
type_id = re.search(r'&type=(.*?)&',type_).group(1)
# print(type_id)
type_ids.append(type_id)
return type_ids
def request_ajax(type_id):
'''
发送ajax请求
:param type_id:
:return:
'''
ajax_url = 'https://movie.douban.com/j/chart/top_list?'
headers = {
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36',
}
#for循环做分页一般用在知道循环多少页的情况下
#while 循环是不知道循环多少页的情况下使用
i = 0
while True:
# 请求参数字典
params = {
'type': type_id,
'interval_id': '100:90',
'action': '',
'start': str(i*20),
'limit': '20',
}
resposne = requests.get(ajax_url,headers=headers,params=params)
#分页结束--到达最后一页
if resposne.text=='[]':
break
#提取数据
json_data = resposne.json()
for data in json_data:
print(data)
#页码+1
i+=1
def main():
#1、获取type值
base_url = 'https://movie.douban.com/chart'
page_content = get_content(base_url,headers=headers)
# print(page_content)
tree = etree.HTML(page_content)
type_urls = tree.xpath('//div[@class="types"]/span/a/@href')
# print(type_urls)
type_ids = get_type_id(type_urls)
#2、请求ajax
for type_id in type_ids:
request_ajax(type_id)
if __name__ == '__main__':
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36',
}
main()
ge_content)
type_urls = tree.xpath(’//div[@class=“types”]/span/a/@href’)
# print(type_urls)
type_ids = get_type_id(type_urls)
#2、请求ajax
for type_id in type_ids:
request_ajax(type_id)
if name == ‘main’:
headers = {
‘user-agent’: ‘Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36’,
}
main()
作业:斗鱼直播通过ajax获取数据。