【爬⾍实践】爬取官⽅新闻标题、正⽂、时间爬⾍⽤的频率较少,每次使⽤都会⼿⽣,特此记录⼀次实战经历。
项⽬需求
要求爬取中“滚动预警”菜单中的⽂章,包括⽂章标题,⽂章正⽂,⽂章时间,并保存为txt⽂件。
项⽬分析
1、判断可爬取的内容
⾸先查看该⽹站的⽂件,发现并不存在该⽂件。因此相关公开信息可正常爬取。
2、确定⽹页的加载模式
⽹页加载可分为静态加载和动态加载。
在⽹页中右键->选择查看源代码,即⽹页的静态代码。在⽹页中右键->检查,可查看浏览器当前渲染的内容。
若两者⼀致,则⽹页是静态加载。此时,通常使⽤的⽅式即可获取到⽹页数据。
若两者不⼀致,⽹页是动态加载。此时需通过开发者后台查看本地向服务器发送的交互性数据(XHR)。
每隔3页,⽹页会短暂卡顿,进⾏加载,同时可以发现多了⼀份XHR数据,如图所⽰,此时,请求的⽹址如上所⽰,url中标记了起始数据和结束数据,同时,⽹页的请求⽅法为POST。
3、查看提交的表单内容
如图所⽰,提交的表单主要有七个数据,查看该⽹站的其他页⾯,可以⼤概猜测:
webid⽤于区分不同的⼤板块,columnid⽤于区分每个⼤板块中的⼩板块,其它属性未知。在翻页过程中,仅有url发⽣变化,提交的表单内容固定。
还可以发现,应急要闻和滑动预警所请求的url相同,区别是表单数据:应急要闻的columnid为29112,滑动预警的columnid为34053。
4、获取⽂章标题、内容与发布时间
通过上⾯的分析,已经可以通过post的⽅式获取各页⽬录的源代码,再次基础上,需要通过⽬录的链接,进⼊到每篇⽂章的页⾯进⾏,标题、正⽂、时间的提取。
通过bs4的函数⼯具以及正则表达式,可将链接内容提取出来,存放到Linklist。
点击链接进⾏跳转,可以发现正⽂内容页⾯使⽤静态加载,此时使⽤get或post的⽅法均可得到⽂章内容。我在这⾥仍沿⽤了之前封装好的post⽅法。
分别提取⽂章标题、内容、时间存储⾄title_list、content_list、time_list。
5、寻规律⾃动翻页
完整代码
import os
from bs4 import BeautifulSoup
import re
import requests
# post得到⽹页并⽤bs4进⾏⽹页解析
def getHtml(url):
header ={'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/52.0.2743.116 Safari/537.36'}
data ={
'col':1,
'webid':'33',
'path':'v/',
# 'columnid': '29112', # 29112对应应急要闻
'columnid':'34053',# 34053对应滚动预警
'sourceContentType':'1',
'unitid':'92715',
'webname':'%E6%B5%8E%E5%8D%97%E5%B8%82%E5%BA%94%E6%80%A5%E7%AE%A1%E7%90%86%E5%B1%80',
'permissiontype':0
}
rep = requests.post(url=url, data=data, headers=header, stream=True).text
# 解析⽹页
soup = BeautifulSoup(rep,'html.parser')
return soup
# 从a标签中切分出具体⽂章链接
def split_link(string):
start_string ='http'
end_string ='.html'
sub_str =""
start = string.find(start_string)
# 只要start不等于-1,说明到了http
while start !=-1:
# 结束的位置
end = string.find(end_string, start)
# 截取字符串结束位置=结束字符串的开始位置+结束字符串的长度
sub_str = string[start:end +len(end_string)]
# 下⼀个开始的位置
# 如果没有下⼀个开始的位置,结束循环
start = string.find(start_string, end)
return sub_str
# 截取⽂章发布时间的年⽉⽇
def split_time(t):
year = t[0:4]
month = t[5:7]
day = t[8:10]
data ="%s-%s-%s"%(year, month, day)
data ="%s-%s-%s"%(year, month, day)
return data
# 获取⼀页中的所有链接
def get_link_list(soup):
# 使⽤正则表达式提取链接内容
p = repile(r'<div class="ajj_clear_box">(.*?)</div>?', re.S)
items = re.findall(p,str(soup))
# print(items)
Linklist =[]
# 返回出各⽹站内容链接
for item in items:
# print(item)
link = split_link(item)
Linklist.append(link)
return Linklist
# 获取单篇⽂章标题、内容与发布时间
def get_title_content(soup_ev):
# ⽂章标题
title = soup_ev.find(name="meta", attrs={"name":"ArticleTitle"})['content']
# print(title)
# ⽂章内容
content = soup_ev.find(name="div", attrs={"id":"zoom"}).findAll(name="span")
# ⽂章发布时间
pub_time = soup_ev.find(name="meta", attrs={"name":"pubdate"})['content']
p_time = split_time(pub_time)
# print(p_time)
return title, content, p_time
# 保存单篇新闻
def save_content(title, content, index, time):
for item in content:
text_content =
# print(text_content)
# 以标题名作为⽂件名,防⽌某些标题含有特殊符号,将其替换为空
sets =['/','\\',':','*','?','"','<','>','|']
for char in title:
if char in sets:
title = place(char,'')
tex_name ="%d%s-%s"%(index, title, time)
# 注:由于每段⽂字是分离的,因此写⼊⽂件模式设定为追加写⼊(a)
# ⽂件夹在主函数内创建
with open(r'./应急要闻/%s.txt'% tex_name, mode='a', encoding='utf-8')as f:
# 每段⽂字进⾏换⾏
f.write(text_content +"\n")
时间正则表达式java''' 滚动预警
with open(r'./滚动预警/%s.txt' % tex_name, mode='a', encoding='utf-8') as f:
# 每段⽂字进⾏换⾏
f.write(text_content + "\n")
'''
# 获取⼀次加载的新闻链接列表
def get_news_list(Linklist):
title_list =[]
content_list =[]
time_list =[]
for item in Linklist:
# item、soup_ev都有可能因返回数据出现异常中断,这⾥对异常数据不作处理,跳过中断try:
soup_ev = getHtml(item)
title, content, p_time = get_title_content(soup_ev)
title_list.append(title)
content_list.append(content)
content_list.append(content)
time_list.append(p_time)
except Exception:
pass
continue
return title_list, content_list, time_list
# 根据⽂章的时间重新进⾏排序(按时间从后到前)
def sort_news(title_list, content_list, time_list):
title_content_time =zip(title_list, content_list, time_list)
sorted_title_content_time =sorted(title_content_time, key=lambda x: x[2], reverse=True)
result =zip(*sorted_title_content_time)
title_list, content_list, time_list =[list(x)for x in result]
return title_list, content_list, time_list
# 保存list中所有新闻
def save_all(title_list, content_list, time_list):
loop =zip(title_list, content_list, time_list)
index =1
for title, content, time in loop:
save_content(title, content, index, time)
index +=1
if __name__ =='__main__':
# 在当前⽬录下创建存储新闻内容的⽂件夹
path = os.getcwd()
file_path = path +'\\'+str("滚动预警")
# file_path = path + '\\' + str("应急要闻")
os.mkdir(file_path)
# 存储每三页的标题、内容、时间
title_list =[]
content_list =[]
time_list =[]
# 存储所有新闻的标题、内容、时间
tol_title_list =[]
tol_content_list =[]
tol_time_list =[]
i =1
while True:
url ='v/module/web/jpage/dataproxy.jsp?startrecord=%d&endrecord=%d&perpage=9'%(i, i +26) soup = getHtml(url)
Linklist = get_link_list(soup)
# 取消下⾯的注释,可打印出每次请求得到的链接数,以显⽰程序正在允许中
# print(len(Linklist))
# print(Linklist)
# 假如爬完所有内容,跳出循环
if Linklist:
title_list, content_list, time_list = get_news_list(Linklist)
tol_d(title_list)
tol_d(content_list)
tol_d(time_list)
else:
break
i = i +27
# print(len(tol_title_list))
# print(len(tol_content_list))
# print(len(tol_time_list))
tol_title_list, tol_content_list, tol_time_list = sort_news(tol_title_list, tol_content_list, tol_time_list)
save_all(tol_title_list, tol_content_list, tol_time_list)
常见报错
1、(‘Connection aborted.’, TimeoutError(10060, ‘由于连接⽅在⼀段时间后没有正确答复或连接的主机没有反应,连接尝试失败。’, None, 10060, None))
解决⽅式:关闭电脑的防⽕墙。
2、Failed to establish a new connection: [WinError 10060] 由于连接⽅在⼀段时间后没有正确答复或连接的主机没有反应,连接尝试失败。’))
问题分析:该报错可能是ip被封或者爬⾍访问速度过快,服务器来不及响应。
解决⽅式:每次gethtml添加time.sleep(1),让每次爬取间隔1秒时间,若仍报错,尝试使⽤代理ip。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论