代码拉取完成,页面将自动刷新
import requests
from lxml import etree
import re #正则表达式
from collections import Counter #统计数量
import sqlite3
#导入线程池
from multiprocessing.dummy import Pool
#jieba分词
from jieba import lcut
import jieba
jieba.initialize() # 手动初始化(可选)
def main():
#新闻种类数组:
#学校要闻、综合新闻、媒体聚焦、理论学习、文明创建、专题网站
#newsType = ["xxyw","zhxw","mtjj","llxx","wmcj","ztwz"]
newsType = ["xxyw"]
#1 爬取网页(根据新闻类型,分别获取信息)
#第一种是学校官方新闻
#第二种是引用外网新闻,只需要获取新闻标题和url(判断url是否包含whpu)
pool = Pool(5)
for newType in newsType:# 里面有7个新闻种类链接
print("开始爬取"+newType)
allList = [] #某类新闻的所有链接
allList = getUrlList(newType)
print("获取该类新闻链接成功!")
#print(allList)
#引入多线程
#datalist = getData(allList) #这里的newType是为了保存到datalist
'''
第一个参数就是需要引用的函数,第二个参数是一个可迭代对象,如nums_list = [1, 2, 9]
它会把需要迭代的元素一个个的传入第一个参数我们的函数中。
因为我们的map会自动将数据作为参数传进去 ;result = pool.map(numsCheng, nums_list)
'''
#报错:getData需要数组,map是迭代为单个str
datalist = pool.map(getOneData, allList) # 函数,所有列表
print("某一类新闻爬取成功!")
#print(datalist)
print("=========================================")
#3 保存数据到sqlite数据库; 数据库名:news.db 表名:newsInfo
dbpath = "news.db" #s数据库名字
saveData(datalist, dbpath) #保存
# 使用完成
pool.close() # pool.close告诉池不要接受任何新工作。
pool.join() # pool.join告诉池等待所有作业完成然后退出,有效地清理池。
print("所有数据保存成功!")
#格式化新闻类型链接, 获得baseurl
#类型包括:学校要闻-xxyw;综合新闻-zhxw;媒体聚焦:mtjj;理论学习:llxx;文明创建:wmcj;专题网站:ztwz
def urlFormat(newsType, pageNum):
baseurl = ""
baseurl = rf"http://news.whpu.edu.cn/xw/{newsType}.htm"
pageSize, _ = getTotalNum(baseurl) #获取当前类型新闻的总页数
#若为第一页则不能添加页码,其他的都要添加
if pageNum != pageSize:
baseurl = rf"http://news.whpu.edu.cn/xw/{newsType}/{pageNum}.htm"
return baseurl
#获得某种类型新闻的所有url
def getUrlList(newsType):
all_url_list = [] # 存放某种类型的新闻数据
# 总页数
baseurl = rf"http://news.whpu.edu.cn/xw/{newsType}.htm"
#有些链接被过滤了,不能直接使用page_nums???
page_nums, _ = getTotalNum(baseurl)
#183是测试数据,应该为 0
# range(start, stop, [step]),每次加上-1,直到0,但是不 包含0
# for i in range(page_nums, 0, -1): #page_nums到 1
#########################测试:控制新闻数量#######################################################
for i in range(page_nums, page_nums-5, -1): #倒数5页条新闻
#########################测试:控制新闻数量#######################################################
# 当前页码对应的页面
url = urlFormat(newsType, i)
# 获取网页html的text文本
page_text = askURL(url)
tree = etree.HTML(page_text)
# 获得新闻链接列表
urls = tree.xpath("//*[@id=\"content\"]/div[4]/ul//a/@href")
#遍历每一条新闻url
for url_one in urls:
'''
此处是格式化一种类型的某一页里面的所有url链接
如果是外网的链接,就丢弃
'''
#print(url_one) href="../info/1005/17129.htm"
url_one = str(url_one)
if '../info' in url_one: ######################这个过滤很多bug#########################
#页面的url格式不全,需要自动补齐
url_one = url_one.replace('../..', 'http://news.whpu.edu.cn')
url_one = url_one.replace('..', 'http://news.whpu.edu.cn')
all_url_list.append(url_one)
#清除重复的url链接,数据量是不是有点大?
# 运用新建字典的方式,去除重复的键
dic = {}
# 字典在创建新的字典时,有重复key则覆盖
all_url_list= dic.fromkeys(all_url_list).keys() #结果为字典
return list(all_url_list)
'''
baseurl = "http://news.whpu.edu.cn/info/1007/16975.htm"
owner=1310939652 #不知道是什么。。。。一个编号====================自己获取
view = getView(baseurl,1310939652) #使用方式
'''
#获取新闻的浏览数量,owner默认为 1310939652
def getView(baseurl, owner):
newNum = (baseurl.split("/")[-1]).split(".")[0] #16975
viewUrl = rf"http://news.whpu.edu.cn/system/resource/code/news/click/dynclicks.jsp?clickid={newNum}&owner={owner}&clicktype=wbnews"
#print(viewUrl)
header = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"}
web_data = requests.get(url=viewUrl, headers = header)
view =int(web_data.text)
return view
#获取关键词,使用jieba分词=======慢慢慢=======
def getKeywords(content):
#text = ''.join(sentences) #将列表中的每个成员以字符''分隔开再拼接成一个字符串
#print(text)
words = lcut(content) #分词
#过滤分词后长度小于1的词语或标点符号,!!!!!!!!
words = filter(lambda word: len(word) > 1, words)
freq = Counter(words) #统计次数
res = freq.most_common(5) #类型为list,一共5条
return res
#方法一:参数为一条url
def getOneData(oneUrl):
data = [] # 保存一篇新闻的全部信息包括:id,类型,url,标题,日期,浏览量,关键字
#1 获取新闻的唯一标识id: http://news.whpu.edu.cn/info/1002/17024.htm则id为 17024
urlId = oneUrl.split('/')[-1].split('.')[0]
data.append(urlId)
#########解析页面才能获得的数据###########
# (2) 逐一解析数据
html = askURL(oneUrl) # 保存获取的网页源码text
tree = etree.HTML(html)
#2 保存传过来的新闻类型(动态加载:../../xw/ztwz.htm)。可以优化,直接获得中文类型:专题网站,而不是ztwz
#//*[@id="content"]/div[1]/ul/li[3]/a
types = tree.xpath("//*[@id=\"content\"]//ul/li[3]/a/@href")[0]
types = types.split("/")[-1].split(".")[0] #获得ztwz字符串
data.append(types)
#3 保存新闻的链接url
data.append(oneUrl)
#4 新闻标题 [为什么有的标题出现\u200b校领导带????]
title = tree.xpath("//*[@id=\"content\"]/div[2]/form/div/ul/li[2]/text()")[0]
data.append(title)
#5 新闻时间: 发布日期:2022-03-22
time = tree.xpath("//*[@id=\"content\"]/div[2]/form/div/ul/li[4]/span[3]/text()")[0]
time = time.split(":")[1]
data.append(time)
#6 新闻浏览量
#这个是动态加载出来的,cccc???????????????
#view = tree.xpath("//*[@id=\"content\"]/div[2]/form/div/ul/li[4]/span[4]/span/text()")
view = getView(oneUrl, 1310939652) #int型????????
data.append(view)
#7 新闻关键字
# 新闻内容
texts = tree.xpath("//div[@class=\"text\"]//text()") #list类型
# 将列表中的每个成员以字符''分隔开再拼接成一个字符串,(省略并strip 同时去掉左右两边的空格)
texts = ''.join(texts)
#清除\r\n
texts = texts.replace('\r', '').replace('\n', '')
keywords = getKeywords(texts)
data.append(keywords)
print(data)
return data #只返回一条数据
#方法二:爬取网页,获取数据,解析数据; 参数为字符串数组
def getData(all_url_list):
datalist = []
#print(type(all_url_list)) #是str类型,根本不是字符串数组
for url in all_url_list:
data = [] # 保存一篇新闻的全部信息包括:id,类型,url,标题,日期,浏览量,关键字
#1 获取新闻的唯一标识id: http://news.whpu.edu.cn/info/1002/17024.htm则id为 17024
urlId = url.split('/')[-1].split('.')[0]
data.append(urlId)
#########解析页面才能获得的数据###########
# (2) 逐一解析数据
html = askURL(url) # 保存获取的网页源码text
tree = etree.HTML(html)
#2 保存传过来的新闻类型(动态加载:../../xw/ztwz.htm)。可以优化,直接获得中文类型:专题网站,而不是ztwz
types = tree.xpath("//*[@id=\"content\"]/div[1]/ul/li[3]/a/@href")[0]
types = types.split("/")[-1].split(".")[0] #获得ztwz字符串
data.append(types)
#3 保存新闻的链接url
data.append(url)
#4 新闻标题 [为什么有的标题出现\u200b校领导带????]
title = tree.xpath("//*[@id=\"content\"]/div[2]/form/div/ul/li[2]/text()")[0]
data.append(title)
#5 新闻时间: 发布日期:2022-03-22
time = tree.xpath("//*[@id=\"content\"]/div[2]/form/div/ul/li[4]/span[3]/text()")[0]
time = time.split(":")[1]
data.append(time)
#6 新闻浏览量
#这个是动态加载出来的,cccc???????????????
#view = tree.xpath("//*[@id=\"content\"]/div[2]/form/div/ul/li[4]/span[4]/span/text()")
view = getView(url, 1310939652) #int型????????
data.append(view)
#7 新闻关键字
# 新闻内容
texts = tree.xpath("//div[@id=\"vsb_content_2\"]//text()") #list类型
# 将列表中的每个成员以字符''分隔开再拼接成一个字符串,(省略并strip 同时去掉左右两边的空格)
texts = ''.join(texts)
#清除\r\n
texts = texts.replace('\r', '').replace('\n', '')
keywords = getKeywords(texts)
data.append(keywords)
#将一条新闻的相关信息存入列表
datalist.append(data)
#else: #url为外网引用链接,只获取标题和url,难以获得id。????
# continue; #先丢弃先丢弃先丢弃先丢弃先丢弃先丢弃先丢弃
print("一类新闻爬取成功!")
return datalist
#获取某种类型新闻的总条数和总页数
def getTotalNum(baseurl):
newNums = 0
pageNums = 0
page_text = askURL(baseurl) #获取页面html内容
# 页面dom树
tree = etree.HTML(page_text)
#获取相关信息:【共3614条 1/181】
page_str = tree.xpath("//*[@id=\"fanye153388\"]/text()")[0]
#print(page_str)
newNums = re.findall(r'[1-9]+', page_str)[0] # + :匹配1个或多个的表达式
pageNums = page_str.split('/')[-1]
pageNums = int(pageNums)
newNums = int(newNums)
return pageNums, newNums
#得到指定的一个url的网页内容。返回页面html的text格式
def askURL(url):
#模拟浏览器头部信息,向服务器发送信息
header = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"}
html = ""
try:
#print(url)
html = requests.get(url=url, headers=header)
except Exception as e:
print(e)
html.encoding = "utf-8"
html = html.text
return html
#3 保存数据(首先要初始化数据库)
def saveData(datalist,dbpath):
#初始化数据库(暂时不需要)
#init_db(dbpath)
#1 连接数据库,获取游标
conn = sqlite3.connect(dbpath)
cur = conn.cursor()
#2 获取sql语句
sqlList = getSql(datalist)
for sql in sqlList:
cur.execute(sql)
conn.commit()
print("保存数据到数据库成功")
conn.close()
#处理datalist列表里面所有的数据,返回sql语句的list集合
def getSql(datalist):
sqlList = []
for data in datalist:
#index:列的下标 len(data)多少列
for index in range(len(data)):
#由于有的数据存入数据库需要的数据类型为str,使用需要转换
if index==0: #id为str,需要转换为int
data[index] = int(data[index])
#[('工作', 28), ('学生', 25), ('坚持', 11), ('大学生', 9), ('调研', 6)]
if index==6: #关键字为list类型,里面是什么类型
keywords = ""
for key,value in data[index]: #key为str类型,value为int类型
keyword = key+':'+str(value) #str类型
keywords = keyword+' '+keywords #空格相隔
data[index] = keywords #list成功变成字符串
sql = "insert or replace into newsInfo(id,type,url,title,day,views,keywords)values(%d,'%s','%s','%s','%s',%d,'%s')" % (data[0],data[1],data[2],data[3],data[4],data[5],data[6])
sqlList.append(sql)
return sqlList
# 创建数据库
def init_db(dbpath):
sql = '''
create table newsInfo(
id int primary key not null,
type varchar,
url varchar,
title varchar,
day varchar,
views int,
keywords varchar);
'''
conn = sqlite3.connect(dbpath)
cursor = conn.cursor()
cursor.execute(sql)
conn.commit()
print("创建数据库成功")
conn.close()
if __name__ == '__main__':
#init_db("news.db") #只能执行一次
main()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。