Python爬虫实践~BeautifulSoup+urllib+Flask实现静态网页的爬取
爬取的网站类型:
论坛类网站类型
涉及主要的第三方模块:
BeautifulSoup:解析、遍历页面
urllib:处理URL请求
Flask:简易的WEB框架
介绍:
本次主要使用urllib获取网页数据,然后通过BeautifulSoup进行页面解析,返回json结构的数据。
功能点:
urllib根据URL通过GET方式获取网页内容;
通过JSON文件配置
解析页面结构,返回JSON结构的数据
提供REST服务进行调用
特点:
1、提供数据描述服务,总页面,每页条数,总条数;
2、增量请求数据,只获取当前时间和上次请求时间之间的数据;
3、控制请求时间间隔,防治IP被封杀
4、分页数据请求
5、修改请求关键字,并记录上次的请求关键字
主要代码结构:
- 公共请求端封装
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from urllib import request
from urllib.parse import quote
import string
import requests # 静态页面基类
class StaticBase():
# 获取网页内容
def __getHTMLText(self,url,code="utf-8"):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = code
return r.text
except:
return ""
# get方式请求数据
def getUrl(self,url,code='utf-8'):
url = quote(url,safe=string.printable)
req = request.Request(url)
req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36')
with request.urlopen(req) as f:
print('Status:',f.status,f.reason)
return f.read().decode(code) #s = StaticBase()
#print(s.getUrl('http://www.baidu.com/','utf-8'))
- 配置文件
{
"host": "http://shangyu.108sq.cn",
"base_url": "http://shangyu.108sq.cn/shuo/search?sertype=4",
"key_words": "污染",
"page_size": 30,
"search_key": "",
"last_request_time": 1562142204.149511,
"request_gap": 60
}
- 解析服务
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from bs4 import BeautifulSoup
from datetime import datetime
import json
from common.staticBase import StaticBase class Shangyh108(StaticBase): __config_file = "config.json" #配置文件
__text = "" #解析的网页内容
__config_dict = {} #配置集合
__url = "" #请求的URL
__keywords = "" #关键字
__last_request_time = 0 #上次请求时间
# 构造函数
def __init__(self):
self.__config_dict = self.__getConfig()
# 查询关键字
if len(self.__config_dict['search_key']) >0 :
self.__keywords = self.__config_dict['search_key']
else:
self.__keywords = self.__config_dict['key_words']
self.__url = self.__getUrl()
# 获取网页内容
def getText(self):
print(self.__url)
self.__text = StaticBase.getUrl(self,self.__url) # 获取第一页内容
def getFirstPageText(self,url=''):
if self.checkRquestTime():
if len(url)==0 :
url = self.__getUrl()
self.__text = StaticBase.getUrl(self,url)
return self.parseHTML()
else:
print("操作频繁请稍后重新")
# 获取下一页
def getNextPage(self,url):
url = self.__config_dict['host']+url
print(url)
self.__text = StaticBase.getUrl(self,url)
return self.parseHTML() # 为防止请求对服务器造成太大压力,控制请求的时间间隔,最少为5分钟
def checkRquestTime(self):
request_gap = self.__config_dict['request_gap']
last_request_time = self.__config_dict['last_request_time']
dt_now = datetime.now().timestamp()
self.__last_request_time = last_request_time # 记录上次请求的时间,为了获取阶段性的数据
if last_request_time == 0: #第一次请求,直接通过
last_request_time = dt_now
elif last_request_time+request_gap > dt_now:
print("请求过度频繁,请稍后重试")
return False
else:
last_request_time = dt_now self.__setConfig('last_request_time',last_request_time)
return True # 获取网页描述信息
def getDesc(self):
self.getText()
soup = BeautifulSoup(self.__text,'html.parser')
obj_count = soup.select('.count')[0]
count_str = str(obj_count.string).replace("(共","").replace("条)","")
count = int(count_str)
pageSize = int(self.__config_dict['page_size'])
host = self.__config_dict['host']
if count % pageSize == 0 :
pages = count//pageSize
else:
pages = count // pageSize + 1
desc = {}
desc['host'] = host
desc['count'] = count
desc['page_size'] = pageSize
desc['total_page'] = pages
# 增加分页的URL
if pages > 0 :
pageUrls = soup.select(".TCPage__middle > a")
page_url = []
for i in range(len(pageUrls)-1) :
tag = pageUrls[i+1]
page_url.append(tag['href'])
desc['page_url'] = page_url
return json.dumps(desc,ensure_ascii=False) # 解析网页内容
def parseHTML(self):
soup = BeautifulSoup(self.__text, 'html.parser')
list_li = soup.select('.TCSayList .TCSayList_li')
data_list = []
for i in range(len(list_li)):
item = {}
temp = list_li[i]
publish_time = temp.select('.TCSayList_li_time')[0]
int_dt = int(publish_time['data-time']) if self.__last_request_time == 0 or self.__last_request_time < int_dt :
# 发布时间
item['publish_time_long'] = publish_time['data-time']
item['publish_time_str'] = datetime.fromtimestamp(int(publish_time['data-time'])).strftime(
'%Y-%m-%d %H:%M:%S') # 数据标签
item['data-tag'] = temp['data-tag']
# 用户
author = temp.select('.TCSayList_li_author')[0]
item['author_name'] = author.string
item['author_url'] = author['href'] # 标题
if len(temp.select('.TCSayList__title a')) >0:
title = temp.select('.TCSayList__title a')[0]
item['title'] = title.string
item['link_url'] = title['href']
# 内容
item['content'] = temp.select('.TCSayList_li_content')[0]['data-short'] data_list.append(item)
return data_list
# 获取请求配置信息
def __getConfig(self):
with open(self.__config_file, "r",encoding="utf-8") as load_f:
load_dict = json.load(load_f)
return load_dict
# 设置配置项
def __setConfig(self,key,value):
self.__config_dict[key] = value
print(self.__config_dict)
with open(self.__config_file,'w',encoding="utf-8") as f:
f.write(json.dumps(self.__config_dict,ensure_ascii=False)) def getKeywords(self):
self.__keywords = input("请输入查询的关键字,多个关键字用“+”连接,默认关键字:环保+污染+投诉,使用默认关键字可直接按Enter:")
if len(self.__keywords) == 0:
self.__keywords = self.__config_dict['key_words']
else:
self.__setConfig("search_key",self.__keywords) # 获取请求的URL
def __getUrl(self):
base_url = self.__config_dict['base_url']
# 组装查询参数
url = base_url + "&key=" + self.__keywords
return url
- REST服务端(目前服务没有暴露很多,但相应服务实现都已经实现)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask,jsonify,abort,request
from changshuo108.shangyu.Shangyh108 import Shangyh108 app = Flask(__name__)
# 支持中文
app.config['JSON_AS_ASCII'] = False
shangyue = Shangyh108()
@app.route('/shangyu108/api/desc',methods=['GET'])
def get_desc():
return shangyue.getDesc() @app.route('/shangyu108/api/first_page',methods=['GET'])
def get_firstPage():
return jsonify({'data':shangyue.getFirstPageText('')}) @app.route('/shangyu108/api/page',methods=['POST'])
def get_article():
if not request.json or not 'url' in request.json:
abort(400)
print(request.json['url'])
return jsonify({'data':shangyue.getNextPage(request.json['url'])}) if __name__ == '__main__':
app.run(debug=True)
爬取的网站类型:
论坛类网站类型
涉及主要的第三方模块:
BeautifulSoup:解析、遍历页面
urllib:处理URL请求
Flask:简易的WEB框架
介绍:
本次主要使用urllib获取网页数据,然后通过BeautifulSoup进行页面解析,返回json结构的数据。
功能点:
urllib根据URL通过GET方式获取网页内容;
通过JSON文件配置
解析页面结构,返回JSON结构的数据
提供REST服务进行调用
特点:
1、提供数据描述服务,总页面,每页条数,总条数;
2、增量请求数据,只获取当前时间和上次请求时间之间的数据;
3、控制请求时间间隔,防治IP被封杀
4、分页数据请求
5、修改请求关键字,并记录上次的请求关键字
主要代码结构:
- 公共请求端封装
#!/usr/bin/env python# -*- coding:utf-8 -*-from urllib import requestfrom urllib.parse import quoteimport stringimport requests# 静态页面基类class StaticBase():# 获取网页内容 使用的requests 库实现def __getHTMLText(self,url,code="utf-8"):try:r = requests.get(url)r.raise_for_status()r.encoding = codereturn r.textexcept:return ""# get方式请求数据 通过urllib记性实现GET请求def getUrl(self,url,code='utf-8'):url = quote(url,safe=string.printable)req = request.Request(url)req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36')with request.urlopen(req) as f:print('Status:',f.status,f.reason)return f.read().decode(code)#s = StaticBase()#print(s.getUrl('http://www.baidu.com/','utf-8'))
- 配置文件
{"host": "http://shangyu.108sq.cn","base_url": "http://shangyu.108sq.cn/shuo/search?sertype=4","key_words": "污染","page_size": 30,"search_key": "","last_request_time": 1562142204.149511,"request_gap": 60}
- 解析服务
#!/usr/bin/env python# -*- coding:utf-8 -*-from bs4 import BeautifulSoupfrom datetime import datetimeimport jsonfrom common.staticBase import StaticBaseclass Shangyh108(StaticBase):__config_file = "config.json" #配置文件__text = "" #解析的网页内容__config_dict = {} #配置集合__url = "" #请求的URL__keywords = "" #关键字__last_request_time = 0 #上次请求时间# 构造函数def __init__(self):self.__config_dict = self.__getConfig()# 查询关键字if len(self.__config_dict['search_key']) >0 :self.__keywords = self.__config_dict['search_key']else:self.__keywords = self.__config_dict['key_words']self.__url = self.__getUrl()# 获取网页内容def getText(self):print(self.__url)self.__text = StaticBase.getUrl(self,self.__url)# 获取第一页内容def getFirstPageText(self,url=''):if self.checkRquestTime():if len(url)==0 :url = self.__getUrl()self.__text = StaticBase.getUrl(self,url)return self.parseHTML()else:print("操作频繁请稍后重新")# 获取下一页def getNextPage(self,url):url = self.__config_dict['host']+urlprint(url)self.__text = StaticBase.getUrl(self,url)return self.parseHTML()# 为防止请求对服务器造成太大压力,控制请求的时间间隔,最少为5分钟def checkRquestTime(self):request_gap = self.__config_dict['request_gap']last_request_time = self.__config_dict['last_request_time']dt_now = datetime.now().timestamp()self.__last_request_time = last_request_time # 记录上次请求的时间,为了获取阶段性的数据if last_request_time == 0: #第一次请求,直接通过last_request_time = dt_nowelif last_request_time+request_gap > dt_now:print("请求过度频繁,请稍后重试")return Falseelse:last_request_time = dt_nowself.__setConfig('last_request_time',last_request_time)return True# 获取网页描述信息def getDesc(self):self.getText()soup = BeautifulSoup(self.__text,'html.parser')obj_count = soup.select('.count')[0]count_str = str(obj_count.string).replace("(共","").replace("条)","")count = int(count_str)pageSize = int(self.__config_dict['page_size'])host = self.__config_dict['host']if count % pageSize == 0 :pages = count//pageSizeelse:pages = count // pageSize + 1desc = {}desc['host'] = hostdesc['count'] = countdesc['page_size'] = pageSizedesc['total_page'] = pages# 增加分页的URLif pages > 0 :pageUrls = soup.select(".TCPage__middle > a")page_url = []for i in range(len(pageUrls)-1) :tag = pageUrls[i+1]page_url.append(tag['href'])desc['page_url'] = page_urlreturn json.dumps(desc,ensure_ascii=False)# 解析网页内容def parseHTML(self):soup = BeautifulSoup(self.__text, 'html.parser')list_li = soup.select('.TCSayList .TCSayList_li')data_list = []for i in range(len(list_li)):item = {}temp = list_li[i]publish_time = temp.select('.TCSayList_li_time')[0]int_dt = int(publish_time['data-time'])if self.__last_request_time == 0 or self.__last_request_time < int_dt :# 发布时间item['publish_time_long'] = publish_time['data-time']item['publish_time_str'] = datetime.fromtimestamp(int(publish_time['data-time'])).strftime('%Y-%m-%d %H:%M:%S')# 数据标签item['data-tag'] = temp['data-tag']# 用户author = temp.select('.TCSayList_li_author')[0]item['author_name'] = author.stringitem['author_url'] = author['href']# 标题if len(temp.select('.TCSayList__title a')) >0:title = temp.select('.TCSayList__title a')[0]item['title'] = title.stringitem['link_url'] = title['href']# 内容item['content'] = temp.select('.TCSayList_li_content')[0]['data-short']data_list.append(item)return data_list# 获取请求配置信息def __getConfig(self):with open(self.__config_file, "r",encoding="utf-8") as load_f:load_dict = json.load(load_f)return load_dict# 设置配置项def __setConfig(self,key,value):self.__config_dict[key] = valueprint(self.__config_dict)with open(self.__config_file,'w',encoding="utf-8") as f:f.write(json.dumps(self.__config_dict,ensure_ascii=False))def getKeywords(self):self.__keywords = input("请输入查询的关键字,多个关键字用“+”连接,默认关键字:环保+污染+投诉,使用默认关键字可直接按Enter:")if len(self.__keywords) == 0:self.__keywords = self.__config_dict['key_words']else:self.__setConfig("search_key",self.__keywords)# 获取请求的URLdef __getUrl(self):base_url = self.__config_dict['base_url']# 组装查询参数url = base_url + "&key=" + self.__keywordsreturn url
- REST服务端(目前服务没有暴露很多,但相应服务实现都已经实现)
#!/usr/bin/env python# -*- coding:utf-8 -*-from flask import Flask,jsonify,abort,requestfrom changshuo108.shangyu.Shangyh108 import Shangyh108app = Flask(__name__)# 支持中文app.config['JSON_AS_ASCII'] = Falseshangyue = Shangyh108()@app.route('/shangyu108/api/desc',methods=['GET'])def get_desc():return shangyue.getDesc()@app.route('/shangyu108/api/first_page',methods=['GET'])def get_firstPage():return jsonify({'data':shangyue.getFirstPageText('')})@app.route('/shangyu108/api/page',methods=['POST'])def get_article():if not request.json or not 'url' in request.json:abort(400)print(request.json['url'])return jsonify({'data':shangyue.getNextPage(request.json['url'])})if __name__ == '__main__':app.run(debug=True)
公众号链接:https://mp.weixin.qq.com/s?__biz=Mzg4MzI3MjM4NQ==&tempkey=MTAxNl9KVjVnVCtVNlo4RUpIZmZXbzBfSVR4dHU4YUhhX3hPNGMxVXdMd1JaQ21OZExlNnNybmJzaVhCT2hkZk85RzZKbzRlYWxFcEk1U2g5bmN4cWJ1QlNmNEdmWlBvVWxGTER2NDM5NjdWa1VIaDVWZlFyUF9EVmtYM0lmNnplRzRjanZsWEo4RUlESTg2YlFkVjBxdDFXbzEwR1UtVVpSd2V5U0R1YUVnfn4%3D&chksm=4f48bebe783f37a8622096cf8cb7d5dfbc5d913e3f1694ea601f51eec5aadddee66271739639#rd
Python爬虫实践~BeautifulSoup+urllib+Flask实现静态网页的爬取的更多相关文章
- Python爬虫入门教程第七讲: 蜂鸟网图片爬取之二
蜂鸟网图片--简介 今天玩点新鲜的,使用一个新库 aiohttp ,利用它提高咱爬虫的爬取速度. 安装模块常规套路 pip install aiohttp 运行之后等待,安装完毕,想要深造,那么官方文 ...
- Python爬虫入门教程 15-100 石家庄政民互动数据爬取
石家庄政民互动数据爬取-写在前面 今天,咱抓取一个网站,这个网站呢,涉及的内容就是 网友留言和回复,特别简单,但是网站是gov的.网址为 http://www.sjz.gov.cn/col/14900 ...
- Python爬虫基础之Urllib
一.随时随地爬取一个网页下来 怎么爬取网页?对网站开发了解的都知道,浏览器访问Url向服务器发送请求,服务器响应浏览器请求并返回一堆HTML信息,其中包括html标签,css样式,js脚本等.Chro ...
- 使用Python爬虫库BeautifulSoup遍历文档树并对标签进行操作详解(新手必学)
为大家介绍下Python爬虫库BeautifulSoup遍历文档树并对标签进行操作的详细方法与函数下面就是使用Python爬虫库BeautifulSoup对文档树进行遍历并对标签进行操作的实例,都是最 ...
- Java分布式爬虫Nutch教程——导入Nutch工程,执行完整爬取
Java分布式爬虫Nutch教程--导入Nutch工程,执行完整爬取 by briefcopy · Published 2016年4月25日 · Updated 2016年12月11日 在使用本教程之 ...
- Python爬虫实践 -- 记录我的第二只爬虫
1.爬虫基本原理 我们爬取中国电影最受欢迎的影片<红海行动>的相关信息.其实,爬虫获取网页信息和人工获取信息,原理基本是一致的. 人工操作步骤: 1. 获取电影信息的页面 2. 定位(找到 ...
- Python爬虫——用BeautifulSoup、python-docx爬取廖雪峰大大的教程为word文档
版权声明:本文为博主原创文章,欢迎转载,并请注明出处.联系方式:460356155@qq.com 廖雪峰大大贡献的教程写的不错,写了个爬虫把教程保存为word文件,供大家方便下载学习:http://p ...
- Python爬虫之BeautifulSoup的用法
之前看静觅博客,关于BeautifulSoup的用法不太熟练,所以趁机在网上搜索相关的视频,其中一个讲的还是挺清楚的:python爬虫小白入门之BeautifulSoup库,有空做了一下笔记: 一.爬 ...
- python爬虫实践
模拟登陆与文件下载 爬取http://moodle.tipdm.com上面的视频并下载 模拟登陆 由于泰迪杯网站问题,测试之后发现无法用正常的账号密码登陆,这里会使用访客账号登陆. 我们先打开泰迪杯的 ...
随机推荐
- 10. Go 语言反射
Go 语言反射 反射是指在程序运行期对程序本身进行访问和修改的能力.程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分.在运行程序时,程序无法获取自身的信息. 支持反射的语言可以在 ...
- HashMap、HashTable 和 ConcurrentHashMap 线程安全问题
一.HashMap HashMap 是线程不安全的. JDK 1.7 HashMap 采用数组 + 链表的数据结构,多线程背景下,在数组扩容的时候,存在 Entry 链死循环和数据丢失问题. JDK ...
- IT兄弟连 HTML5教程 CSS3揭秘 CSS3概述
对于Web开发者来说,CSS3不只是一门新奇的技术,更重要的是这些全新概念的Web应用给开发人员带来了无限的可能性,也极大地提高了开发效率.我们不必再依赖图片或者JavaScript去完成圆角.多背景 ...
- java获取月的第一天和最后一天
在Java中获取月的第一天和最后一天主要是通过Calendar对象来实现. /** * 获取月的第一天 * * @param month 月 */ private String getMonthBeg ...
- vue的provide和inject特性
由来 组件之间的通信可以通过props和$emit的方式进行通信,但是如果组件之间的关系非常复杂的话,通过以上的方式会很麻烦,并且程序会非常脆弱,没有建中性可言. 在==vue2.2.0 中新增pro ...
- 动态数组原理【Java实现】(六)
前言 接下来我们进入集合学习,看过很多文章一上来就是讲解原理感觉会特别枯燥,任何成熟解决方案的出现都是为了解决问题,若通过实际问题引入然后再来讲解原理想必学起来必定事半功倍,从我写博客的那一天起,我就 ...
- 【HNOI 2017】礼物
Problem Description 我的室友最近喜欢上了一个可爱的小女生.马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她.每个手环上各有 \(n\) 个装饰物,并且每个装饰物 ...
- Linux 资源监控整体分析-TOP
一.top 第一行,任务队列信息,同 uptime 命令的执行结果 系统时间:15:23:10 运行时间:up 236 day,4min, 当前登录用户: 2个 user 负载均衡(uptime) ...
- $和jquery的关系
$和jquery的关系 $其实是jQuery的别名 一般直接使用$符号 在许多JavaScript库中都会有$作为标记.如果同时使用多个JavaScript库时难免会出现冲突. 解决方法:重新设置jQ ...
- Centos下,Docker部署Yapi接口管理平台
前言介绍 Yapi 由 YMFE 开源,旨在为开发.产品.测试人员提供更优雅的接口管理服务,可以帮助开发者轻松创建.发布.维护 API. 项目地址:https://github.com/YMFE/ya ...