python爬虫-爬坑之路
背景简介
爬取外国的某两个网站的数据,网站都没有被墙,爬取三种数据。
- A: 爬取页面并存储到数据库
- B: 爬取页面内的表格内数据并存储到数据库
- C: 爬取页面,分析页面并将页面的所有数据分类存入数据库,且页面内存在下级页面,也需要进行同样的操作
python包选取以及使用
连接链接
在windows电脑上编写调试代码,在linux服务器上运行代码
由于包的差异原因,根据系统选择了两种不同的连接方式(非最佳选择)
windows - urllib3
linux - pycurl、urllib(pycurl连接GET类型的链接时,需要使用urllib.parse对该链接的参数数据进行处理)
注:以下部分处理方法是经对该网站的所有测试,包括连接速度、连接时长、错误类型等进行尽量全面的测试之后采取的方法,不适用所有网站,需要酌情使用
urllib3
# method: 连接链接的方式-GET/POST
# url: 链接地址
# data: 连接链接时需要传输的参数数据
def getHtmlByLib(method, url, data):
try:
http = urllib3.PoolManager(timeout=1000) # 经测试得出:外国网站的连接速度由于时差原因会有不同的延迟,设置超时timeout为1000秒
r = http.request(method, url, fields=data)
html = r.data.decode("utf-8", "ignore") # 将网站页面源代码转换为utf-8时会报转换错误,衡量后使用 ignore 模式,会忽略转换错误的代码
return html
except:
return getHtmlByLib(method, url, data) # 在连接失败或其他错误发生时,重新连接该地址
pycurl
class htmlContents:
def __init__(self):
self.contents = ''
def callback(self, curl):
self.contents = self.contents + curl.decode("utf-8", "ignore")
def getHtmlByCurl(method, url, data):
t = htmlContents()
curl = pycurl.Curl()
# 设置连接链接时的传输参数
if(len(data) > 0):
curl.setopt(pycurl.POSTFIELDS, urllib.parse.urlencode(data))
# 设置头部
headers = ["Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)"]
curl.setopt(pycurl.HTTPHEADER, headers)
# 连接时长与curl的连接时长
curl.setopt(pycurl.CONNECTTIMEOUT, 1000)
curl.setopt(pycurl.TIMEOUT, 900)
# 传输速度 传输速度小于1字节/秒的状态持续90秒,该连接就会终止
curl.setopt(pycurl.LOW_SPEED_TIME, 90)
curl.setopt(pycurl.LOW_SPEED_LIMIT, 1)
# 连接成功以后的处理方法
curl.setopt(pycurl.WRITEFUNCTION, t.callback)
curl.setopt(pycurl.ENCODING, 'gzip, deflate')
curl.setopt(pycurl.URL, url)
# 设置连接以及下载速度的进度条展示
curl.setopt(pycurl.NOPROGRESS, 0)
# 把cookie保存在该文件中
# curl.setopt(pycurl.COOKIEFILE, "cookie_file_name")
# curl.setopt(pycurl.COOKIEJAR, "cookie_file_name")
# POST方式
if(method == "POST"):
curl.setopt(pycurl.POST, 1)
try:
curl.perform()
except pycurl.error as e:
curl.close()
return getHtmlByCurl(method, url, data)
# 获取HTTP_CODE
httpCode = curl.getinfo(curl.HTTP_CODE)
curl.close()
if(httpCode != 200):
return getHtmlByCurl(method, url, data)
# 页面内容
return t.contents
处理页面
bs4/json
爬取页面(A)
评价 : 比较简单,可以作为入门的爬虫,不是单纯的抓取页面,需要获取一些页面内的简单的数据。
使用bs4.BeautifulSoup
进行页面数据的格式化
soup = BeautifulSoup(html, features="html.parser")
大略步骤如下
- 获取所有国家
options = soup.find("select", id="country6").find_all("option")
- 根据国家ID连接链接获取报告列表,解析列表内数据,获取该国家每一年的每份报告的
是否存在
以及报告链接
- 连接报告链接获取页面源代码,并根据需求删除代码内节点树的某些节点
- 存入数据库
知识点
BeautifulSoup
的find_all()
以及find()
方法的使用- find_all() - 获取某个节点下的所有符合条件的节点,不单止子节点,而是所有子孙节点内符合条件的节点
- find() - 获取左右子孙节点内第一个符合条件的节点
BeautifulSoup
的删除节点事件、删除节点删除节点事件
divs = soup.find_all("div") for div in divs: if(div.has_attr('onmouseover')): del div["onmouseover"]
删除节点 -
div.decompose()
BeautifulSoup
输出页面源代码 -print(soup.prettify())
获取页面内的数据并处理(B)
爬取页面内的表格内数据并存储到数据库
评价:需求A的进阶型,主要针对选择页面内下拉列表的选项之后的请求的处理,主要处理json数据,需要对页面内JS方法的理解、在浏览器内使用开发者工具时的有效链接筛选
大略步骤如下:
- 获取第一个页面,解析页面源代码,了解后续操作所产生的JS事件以及影响,并通过浏览器开发者工具筛选出有效链接
- 连接第一步筛选出的有效链接,获取该链接传输来的json数据
- 获取最终目标链接所需要的传输参数。从第二步的json数据中获取;从第一部的初始页面获取;
- 连接目标链接,传输参数数据,并处理最终数据,存入数据库
知识点
该网站对连接次数做出了限制,会返回409状态码,并告知
USAGE LIMIT: Hourly usage limit of 100 actions reached. You may resume use of this service at XXXX-XX-XXT03:43:10Z
代码调整:1. 连接链接时设置休眠时间,
time.sleep(10)
,可以减少409状态码的出现次数;2. 出现409状态码时,休眠10分钟time.sleep(60*10)
字符串转换为json
import json jsonData = json.loads(data)
处理页面内所有数据并存储入数据库(C)
评价:由于该页面内容的多变性,数据处理方式需要更兼容,故认为为B需求的进阶型,基于B需求之后可以更容易筛选出有效链接,主要处理table内数据。
大略步骤如下:
- 获取第一个页面,获取页面内容并通过浏览器开发者工具筛选出有效链接
- 连接第一步筛选出的有效链接,获取页面内的table内容以及需要的数据,包括URL
- 连接table内的URL并获取页面源代码,使用
BeautifulSoup
对页面内容进行处理,获取需要的数据
知识点
table的tr/td处理,子节点获取
tableChoisir = soup.find("table", attrs={"class": "TableChoisir"}) trsList = [] for trChild in tableChoisir.children: # 子节点除了html节点以外,如换行、空白字符等也被视为子节点 trChild = formatString(str(trChild)) if len(trChild.strip(" ")) > 0: trSoup = bsHtml(trChild) trsList.append(trSoup)
获取节点内容
title = trSoup.find("td", attrs={"class": "topbigtabletitle27"}).get_text()
总结叙述
- 使用
bs4.BeautifulSoup
可以很轻松的获取页面节点的所有内容 pycurl
的连接速度优于urllib3
,同时也需要设置很多参数,pycurl
可视为linux下的curl
命令的封装,pycurl
的参数设置可参考libcurl
原文地址:https://www.cnblogs.com/fengzzi/p/11008655.html
- Android深入理解JNI(二)类型转换、方法签名和JNIEnv
- 探讨通过Feign配合Hystrix进行调用时异常的处理
- 小窗播放视频的原理和实现(上)
- 一种Android App在Native层动态加载so库的方案
- java的双缓冲技术
- application之OnLowMemory()和 OnTrimMemory(level)讲解
- React Native组件(一)组件的生命周期
- Spring Cloud构建微服务架构:服务消费(基础)【Dalston版】
- Android解析ClassLoader(一)Java中的ClassLoader
- Android学习笔记(一)之仿正点闹钟时间齿轮滑动的效果
- Android解析WindowManager(三)Window的添加过程
- Spring Cloud构建微服务架构:服务消费(Ribbon)【Dalston版】
- Android解析WindowManager(一)WindowManager体系
- ios9 http请求失败的问题
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 陶瓷PCB电路板到底好在哪?
- Mysql常用函数——告别复杂sql
- Spring Boot读取配置文件的几种方式
- python菜鸟教程 | if else 判断
- Java 语言中十大“坑爹”功能!
- R语言生存分析可视化分析
- 全平台轻量开源verilog仿真工具iverilog+GTKWave使用教程
- R语言时间序列和ARIMA模型预测拖拉机销售的制造案例研究
- Windows10下安装linux子系统学习笔记
- 项目实践 | 从零开始学习Deep SORT+YOLO V3进行多目标跟踪(附注释项目代码)
- [OHIF-Viewers]医疗数字阅片-医学影像-Module: Panel-自定义面板-中-es6-Object.defineProperty()定义属性
- (数据科学学习手札90)Python+Kepler.gl轻松制作时间轮播地图
- WEB前端安全自查和加固
- 硬核!IDEA 中使用 Git 完整入门教程!
- 神器你值得拥有——CoolFormat代码一键自动格式化工具,支持Verilog