spider-04
发布日期:2021-06-29 12:07:04
浏览次数:2
分类:技术文章
本文共 15360 字,大约阅读时间需要 51 分钟。
Day04笔记
动态加载数据抓取-Ajax
-
特点
【1】右键 -> 查看网页源码中没有具体数据【2】滚动鼠标滑轮或其他动作时加载,或者页面局部刷新
-
抓取
【1】F12打开控制台,页面动作抓取网络数据包【2】抓取json文件URL地址 2.1) 控制台中 XHR :异步加载的数据包 2.2) XHR -> QueryStringParameters(查询参数)
豆瓣电影数据抓取案例
-
目标
【1】地址: 豆瓣电影 - 排行榜 - 剧情【2】目标: 电影名称、电影评分
-
F12抓包(XHR)
【1】Request URL(基准URL地址) :https://movie.douban.com/j/chart/top_list?【2】Query String(查询参数) # 抓取的查询参数如下: type: 13 # 电影类型 interval_id: 100:90 action: '' start: 0 # 每次加载电影的起始索引值 0 20 40 60 limit: 20 # 每次加载的电影数量
-
代码实现 - 全站抓取
"""豆瓣电影 - 全站抓取"""import requestsfrom fake_useragent import UserAgentimport timeimport randomimport reimport jsonclass DoubanSpider: def __init__(self): self.url = 'https://movie.douban.com/j/chart/top_list?' self.i = 0 # 存入json文件 self.f = open('douban.json', 'w', encoding='utf-8') self.all_film_list = [] def get_agent(self): """获取随机的User-Agent""" return UserAgent().random def get_html(self, params): headers = { 'User-Agent':self.get_agent()} html = requests.get(url=self.url, params=params, headers=headers).text # 把json格式的字符串转为python数据类型 html = json.loads(html) self.parse_html(html) def parse_html(self, html): """解析""" # html: [{},{},{},{}] item = { } for one_film in html: item['rank'] = one_film['rank'] item['title'] = one_film['title'] item['score'] = one_film['score'] print(item) self.all_film_list.append(item) self.i += 1 def run(self): # d: {'剧情':'11','爱情':'13','喜剧':'5',...,...} d = self.get_d() # 1、给用户提示,让用户选择 menu = '' for key in d: menu += key + '|' print(menu) choice = input('请输入电影类别:') if choice in d: code = d[choice] # 2、total: 电影总数 total = self.get_total(code) for start in range(0,total,20): params = { 'type': code, 'interval_id': '100:90', 'action': '', 'start': str(start), 'limit': '20' } self.get_html(params=params) time.sleep(random.randint(1,2)) # 把数据存入json文件 json.dump(self.all_film_list, self.f, ensure_ascii=False) self.f.close() print('数量:',self.i) else: print('请做出正确的选择') def get_d(self): """{'剧情':'11','爱情':'13','喜剧':'5',...,...}""" url = 'https://movie.douban.com/chart' html = requests.get(url=url,headers={ 'User-Agent':self.get_agent()}).text regex = '' pattern = re.compile(regex, re.S) # r_list: [('剧情','11'),('喜剧','5'),('爱情':'13')... ...] r_list = pattern.findall(html) # d: {'剧情': '11', '爱情': '13', '喜剧': '5', ..., ...} d = { } for r in r_list: d[r[0]] = r[1] return d def get_total(self, code): """获取某个类别下的电影总数""" url = 'https://movie.douban.com/j/chart/top_list_count?type={}&interval_id=100%3A90'.format(code) html = requests.get(url=url,headers={ 'User-Agent':self.get_agent()}).text html = json.loads(html) return html['total']if __name__ == '__main__': spider = DoubanSpider() spider.run()
json解析模块
-
json.loads(json)
【1】作用 : 把json格式的字符串转为Python数据类型【2】示例 : html = json.loads(res.text)
-
json.dump(python,f,ensure_ascii=False)
【1】作用 把python数据类型 转为 json格式的字符串,一般让你把抓取的数据保存为json文件时使用 # 不加 S 是保存到文件之中,dumps 是在程序中使用【2】参数说明 2.1) 第1个参数: python类型的数据(字典,列表等) 2.2) 第2个参数: 文件对象 2.3) 第3个参数: ensure_ascii=False 序列化时编码,可以显示中文 【3】示例代码 # 示例1 import json item = { 'name':'QQ','app_id':1} with open('小米.json','a') as f: json.dump(item,f,ensure_ascii=False) # 示例2 import json item_list = [] for i in range(3): item = { 'name':'QQ','id':i} item_list.append(item) with open('xiaomi.json','a') as f: json.dump(item_list,f,ensure_ascii=False)
-
json模块总结
# 爬虫最常用【1】数据抓取 - json.loads(html) 将响应内容由: json 转为 python【2】数据保存 - json.dump(item_list,f,ensure_ascii=False) 将抓取的数据保存到本地 json文件# 抓取数据一般处理方式【1】txt文件【2】csv文件【3】json文件【4】MySQL数据库【5】MongoDB数据库【6】Redis数据库
多线程爬虫
-
应用场景
【1】多进程 :CPU密集程序【2】多线程 :爬虫(网络I/O)、本地磁盘I/O
知识点回顾
-
队列
【1】导入模块 from queue import Queue【2】使用 q = Queue() q.put(url) q.get() # 当队列为空时,阻塞 q.empty() # 判断队列是否为空,True/False【3】q.get()解除阻塞方式 3.1) q.get(block=False) 3.2) q.get(block=True,timeout=3) 3.3) if not q.empty(): q.get()
-
线程模块
# 导入模块from threading import Thread# 使用流程 t = Thread(target=函数名) # 创建线程对象t.start() # 创建并启动线程t.join() # 阻塞等待回收线程# 如何创建多线程t_list = []for i in range(5): t = Thread(target=函数名) t_list.append(t) t.start()for t in t_list: t.join()
-
线程锁
from threading import Locklock = Lock()lock.acquire()lock.release()【注意】上锁成功后,再次上锁会阻塞
-
多线程爬虫示例代码
# 抓取豆瓣电影剧情类别下的电影信息"""豆瓣电影 - 剧情 - 抓取"""import requestsfrom fake_useragent import UserAgentimport timeimport randomfrom threading import Thread,Lockfrom queue import Queueclass DoubanSpider: def __init__(self): self.url = 'https://movie.douban.com/j/chart/top_list?type=13&interval_id=100%3A90&action=&start={}&limit=20' self.i = 0 # 队列 + 锁 self.q = Queue() self.lock = Lock() def get_agent(self): """获取随机的User-Agent""" return UserAgent().random def url_in(self): """把所有要抓取的URL地址入队列""" for start in range(0,684,20): url = self.url.format(start) # url入队列 self.q.put(url) # 线程事件函数:请求+解析+数据处理 def get_html(self): while True: # 从队列中获取URL地址 # 一定要在判断队列是否为空 和 get() 地址 前后加锁,防止队列中只剩一个地址时出现重复判断 self.lock.acquire() if not self.q.empty(): headers = { 'User-Agent': self.get_agent()} url = self.q.get() self.lock.release() html = requests.get(url=url, headers=headers).json() self.parse_html(html) else: # 如果队列为空,则最终必须释放锁 self.lock.release() break def parse_html(self, html): """解析""" # html: [{},{},{},{}] item = { } for one_film in html: item['rank'] = one_film['rank'] item['title'] = one_film['title'] item['score'] = one_film['score'] print(item) # 加锁 + 释放锁 self.lock.acquire() self.i += 1 self.lock.release() def run(self): # 先让URL地址入队列 self.url_in() # 创建多个线程,开干吧 t_list = [] for i in range(1): t = Thread(target=self.get_html) t_list.append(t) t.start() for t in t_list: t.join() print('数量:',self.i)if __name__ == '__main__': start_time = time.time() spider = DoubanSpider() spider.run() end_time = time.time() print('执行时间:%.2f' % (end_time-start_time))
selenium+PhantomJS/Chrome/Firefox
-
selenium
【1】定义 1.1) 开源的Web自动化测试工具 【2】用途 2.1) 对Web系统进行功能性测试,版本迭代时避免重复劳动 2.2) 兼容性测试(测试web程序在不同操作系统和不同浏览器中是否运行正常) 2.3) 对web系统进行大数量测试 【3】特点 3.1) 可根据指令操控浏览器 3.2) 只是工具,必须与第三方浏览器结合使用 【4】安装 4.1) Linux: sudo pip3 install selenium 4.2) Windows: python -m pip install selenium
-
PhantomJS浏览器
【1】定义 phantomjs为无界面浏览器(又称无头浏览器),在内存中进行页面加载,高效 【2】下载地址 2.1) chromedriver : 下载对应版本 http://npm.taobao.org/mirrors/chromedriver/ 2.2) geckodriver https://github.com/mozilla/geckodriver/releases 2.3) phantomjs https://phantomjs.org/download.html【3】Ubuntu安装 3.1) 下载后解压 : tar -zxvf geckodriver.tar.gz 3.2) 拷贝解压后文件到 /usr/bin/ (添加环境变量) sudo cp geckodriver /usr/bin/ 3.3) 添加可执行权限 sudo chmod 777 /usr/bin/geckodriver【4】Windows安装 4.1) 下载对应版本的phantomjs、chromedriver、geckodriver 4.2) 把chromedriver.exe拷贝到python安装目录的Scripts目录下(添加到系统环境变量) # 查看python安装路径: where python 4.3) 验证 cmd命令行: chromedriver ***************************总结**************************************【1】解压 - 放到用户主目录(chromedriver、geckodriver、phantomjs)【2】拷贝 - sudo cp /home/tarena/chromedriver /usr/bin/【3】权限 - sudo chmod 777 /usr/bin/chromedriver# 验证【Ubuntu | Windows】ipython3from selenium import webdriverwebdriver.Chrome()或者webdriver.Firefox()【mac】ipython3from selenium import webdriverwebdriver.Chrome(executable_path='/Users/xxx/chromedriver')或者webdriver.Firefox(executable_path='/User/xxx/geckodriver')
-
示例代码
"""示例代码一:使用 selenium+浏览器 打开百度"""# 导入seleinum的webdriver接口from selenium import webdriverimport time# 创建浏览器对象browser = webdriver.Chrome()browser.get('http://www.baidu.com/')# 5秒钟后关闭浏览器time.sleep(5)browser.quit()
"""示例代码二:打开百度,搜索赵丽颖,点击搜索,查看"""from selenium import webdriverimport time# 1.创建浏览器对象 - 已经打开了浏览器browser = webdriver.Chrome()# 2.输入: http://www.baidu.com/browser.get('http://www.baidu.com/')# 3.找到搜索框,向这个节点发送文字: 赵丽颖browser.find_element_by_xpath('//*[@id="kw"]').send_keys('赵丽颖')# 4.找到 百度一下 按钮,点击一下browser.find_element_by_xpath('//*[@id="su"]').click()
-
浏览器对象(browser)方法
【1】browser.get(url=url) - 地址栏输入url地址并确认 【2】browser.quit() - 关闭浏览器【3】browser.close() - 关闭当前页【4】browser.page_source - HTML结构源码【5】browser.page_source.find('字符串') 从html源码中搜索指定字符串,没有找到返回:-1,经常用于判断是否为最后一页【6】browser.maximize_window() - 浏览器窗口最大化
-
定位节点八种方法
【1】单元素查找('结果为1个节点对象') 1.1) 【最常用】browser.find_element_by_id('id属性值') 1.2) 【最常用】browser.find_element_by_name('name属性值') 1.3) 【最常用】browser.find_element_by_class_name('class属性值') 1.4) 【最万能】browser.find_element_by_xpath('xpath表达式') 1.5) 【匹配a节点时常用】browser.find_element_by_link_text('链接文本') 1.6) 【匹配a节点时常用】browser.find_element_by_partical_link_text('部分链接文本') 1.7) 【最没用】browser.find_element_by_tag_name('标记名称') 1.8) 【较常用】browser.find_element_by_css_selector('css表达式')【2】多元素查找('结果为[节点对象列表]') 2.1) browser.find_elements_by_id('id属性值') 2.2) browser.find_elements_by_name('name属性值') 2.3) browser.find_elements_by_class_name('class属性值') 2.4) browser.find_elements_by_xpath('xpath表达式') 2.5) browser.find_elements_by_link_text('链接文本') 2.6) browser.find_elements_by_partical_link_text('部分链接文本') 2.7) browser.find_elements_by_tag_name('标记名称') 2.8) browser.find_elements_by_css_selector('css表达式')
-
猫眼电影示例
from selenium import webdriverimport timeurl = 'https://maoyan.com/board/4'browser = webdriver.Chrome()browser.get(url)def get_data(): # 基准xpath: [
, ] li_list = browser.find_elements_by_xpath('//*[@id="app"]/div/div/div[1]/dl/dd') for li in li_list: item = { } # info_list: ['1', '霸王别姬', '主演:张国荣', '上映时间:1993-01-01', '9.5'] info_list = li.text.split('\n') item['number'] = info_list[0] item['name'] = info_list[1] item['star'] = info_list[2] item['time'] = info_list[3] item['score'] = info_list[4] print(item)while True: get_data() try: browser.find_element_by_link_text('下一页').click() time.sleep(2) except Exception as e: print('恭喜你!抓取结束') browser.quit() break -
节点对象操作
【1】文本框操作 1.1) node.send_keys('') - 向文本框发送内容 1.2) node.clear() - 清空文本 1.3) node.get_attribute('value') - 获取文本内容 【2】按钮操作 1.1) node.click() - 点击 1.2) node.is_enabled() - 判断按钮是否可用 1.3) node.get_attribute('value') - 获取按钮文本
chromedriver设置无界面模式
from selenium import webdriveroptions = webdriver.ChromeOptions()# 添加无界面参数options.add_argument('--headless')browser = webdriver.Chrome(options=options)
selenium - 鼠标操作
from selenium import webdriver# 导入鼠标事件类from selenium.webdriver import ActionChainsdriver = webdriver.Chrome()driver.get('http://www.baidu.com/')# 移动到 设置,perform()是真正执行操作,必须有element = driver.find_element_by_xpath('//*[@id="u1"]/a[8]')ActionChains(driver).move_to_element(element).perform()# 单击,弹出的Ajax元素,根据链接节点的文本内容查找driver.find_element_by_link_text('高级搜索').click()
今日作业
Day04回顾
-
requests.get()参数
【1】url【2】proxies -> { } proxies = { 'http':'http://1.1.1.1:8888', 'https':'https://1.1.1.1:8888' }【3】timeout【4】headers
-
requests.post()
data : 字典,Form表单数据
-
常见的反爬机制及处理方式
【1】Headers反爬虫 1.1) 检查: Cookie、Referer、User-Agent 1.2) 解决方案: 通过F12获取headers,传给requests.get()方法 【2】IP限制 2.1) 网站根据IP地址访问频率进行反爬,短时间内限制IP访问 2.2) 解决方案: a) 构造自己IP代理池,每次访问随机选择代理,经常更新代理池 b) 购买开放代理或私密代理IP c) 降低爬取的速度 【3】User-Agent限制 3.1) 类似于IP限制,检测频率 3.2) 解决方案: 构造自己的User-Agent池,每次访问随机选择 a> fake_useragent模块 b> 新建py文件,存放大量User-Agent c> 程序中定义列表,存放大量的User-Agent 【4】对响应内容做处理 4.1) 页面结构和响应内容不同 4.2) 解决方案: 打印并查看响应内容,用xpath或正则做处理 【5】JS加密 5.1) 抓取到对应的JS文件,寻找加密算法 5.2) 用Python实现加密算法,生成指定的参数
-
有道翻译过程梳理
【1】打开首页【2】准备抓包: F12开启控制台 【3】寻找地址 3.1) 页面中输入翻译单词,控制台中抓取到网络数据包,查找并分析返回翻译数据的地址 F12-Network-XHR-Headers-Grneral-Request URL 【4】发现规律 4.1) 找到返回具体数据的地址,在页面中多输入几个单词,找到对应URL地址 4.2) 分析对比 Network - All(或者XHR) - Form Data,发现对应的规律【5】寻找JS加密文件 5.1) 控制台右上角 ...->Search->搜索关键字->单击->跳转到Sources,左下角格式化符号{ } 【6】查看JS代码 6.1) 搜索关键字,找到相关加密方法,用python实现加密算法 【7】断点调试 7.1) JS代码中部分参数不清楚可通过断点调试来分析查看 【8】完善程序
-
Ajax动态加载数据抓取流程
【1】F12打开控制台,执行页面动作抓取网络数据包【2】抓取json文件URL地址 2.1) 控制台中 XHR :找到异步加载的数据包 2.2) GET请求: Network -> XHR -> URL 和 Query String Parameters(查询参数) 2.3) POST请求:Network -> XHR -> URL 和 Form Data
-
json模块
【1】抓取的json数据转为python数据类型 1.1) html = json.loads('[{},{},{}]') 1.2) html = requests.get(url=url,headers=headers).json() 1.3) html = requests.post(url=url,data=data,headers=headers).json() 【2】抓取数据保存到json文件 import json with open('xxx.json','w') as f: json.dump([{ },{ },{ }],f,ensure_ascii=False)
-
数据抓取最终梳理
【1】响应内容中存在 1.1) 确认抓取数据在响应内容中是否存在 1.2) 分析页面结构,观察URL地址规律 a) 大体查看响应内容结构,查看是否有更改 -- (百度视频案例) b) 查看页面跳转时URL地址变化,查看是否新跳转 -- (民政部案例) 1.3) 开始码代码进行数据抓取【2】响应内容中不存在 2.1) 确认抓取数据在响应内容中是否存在 2.2) F12抓包,开始刷新页面或执行某些行为,主要查看XHR异步加载数据包 a) GET请求: Request URL、Request Headers、Query String Paramters b) POST请求:Request URL、Request Headers、FormData 2.3) 观察查询参数或者Form表单数据规律,如果需要进行进一步抓包分析处理 a) 比如有道翻译的 salt+sign,抓取并分析JS做进一步处理 b) 此处注意请求头中的Cookie和Referer以及User-Agent 2.4) 使用res.json()获取数据,利用列表或者字典的方法获取所需数据
-
多线程爬虫梳理
【1】所用到的模块 1.1) from threading import Thread 1.2) from threading import Lock 1.3) from queue import Queue【2】整体思路 2.1) 创建URL队列: q = Queue() 2.2) 产生URL地址,放入队列: q.put(url) 2.3) 线程事件函数: 从队列中获取地址,开始抓取: url = q.get() 2.4) 创建多线程,并运行 【3】代码结构 def __init__(self): """创建URL队列""" self.q = Queue() self.lock = Lock() def url_in(self): """生成待爬取的URL地址,入队列""" pass def parse_html(self): """线程事件函数,获取地址,进行数据抓取""" while True: self.lock.acquire() if not self.q.empty(): url = self.q.get() self.lock.release() else: self.lock.release() break def run(self): self.url_in() t_list = [] for i in range(3): t = Thread(target=self.parse_html) t_list.append(t) t.start() for th in t_list: th.join() 【4】队列要点: q.get()防止阻塞方式 4.1) 方法1: q.get(block=False) 4.2) 方法2: q.get(block=True,timeout=3) 4.3) 方法3: if not q.empty(): q.get()
转载地址:https://blog.csdn.net/z_202041/article/details/117944899 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月19日 23时01分52秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
mysql数据库操作基础
2019-04-29
Mariadb基础管理
2019-04-29
awk 的内置变量 NF、NR、FNR、FS、OFS、RS、ORS
2019-04-29
CentOS系统内核升级攻略
2019-04-29
linux系统时区修改(Debian的主机和docker)
2019-04-29
docker-compose 安装
2019-04-29
crontab 定时任务
2019-04-29
查看docker veth pair与宿主机上网卡的对应关系
2019-04-29
使用 GitLab CI 进行持续集成的一些踩坑
2019-04-29
企业云盘给贸易业带来新的效益
2019-04-29
Linux入门常用命令
2019-04-29
Spring整理
2019-04-29
SpringMvc加强
2019-04-29
初识Vue全家桶 Nuxt.js(一)
2019-04-29
基本路由及动态路由(二)
2019-04-29
视图:默认模板+默认布局(自定义布局)+nuxt.js页面(三)
2019-04-29