php网页抓取标题(爬取济南市中“滚动预警”菜单中的文章标题、内容与发布时间)

优采云 发布时间: 2022-01-19 12:01

  php网页抓取标题(爬取济南市中“滚动预警”菜单中的文章标题、内容与发布时间)

  爬虫用的比较少,每次用都会手生,特此记录下实战经验。

  项目要求

  需要爬取济南市政网“滚动预警”菜单中的文章,包括文章标题、文章正文、文章时间,并保存为一个txt文件。

  项目分析1、确定可以爬取什么

  首先查看网站的robots.txt文件,发现该文件不存在。因此,可以正常抓取相关公开信息。

  2、确定页面的加载方式

  网页加载可以分为静态加载和动态加载。

  网页右键->选择查看源代码,即网页的静态代码。在网页上右击-> Inspect 查看浏览器当前呈现的内容。

  如果两者一致,则静态加载网页。此时,通常可以使用requests.get获取网页数据。

  如果两者不一致,则动态加载网页。这时候需要通过开发者后台查看本地发送到服务器的交互数据(XHR)。

  

  每3页,网页会冻结一小段时间,然后加载。同时可以找到一个额外的XHR数据,如图。此时请求的URL如上图所示,并且在URL中标注了开始数据和结束数据。同时网页的请求方式为POST。

  3、查看提交的表单内容

  

  如图所示,提交的表单主要收录七条数据。看看网站的其他页面,大致可以猜到:

  webid用来区分不同的大板块,columnid用来区分各个大板块中的小板块,其他属性未知。翻页过程中,只有url发生变化,提交的表单内容是固定的。

  还可以发现,紧急新闻和sliding alerts请求的url是一样的,不同的是form数据:紧急新闻的columnid是29112,sliding alert的columnid是34053。

  4、获取文章标题、内容和发表时间

  通过上面的分析,已经可以通过post的方式获取到各个页面目录的源码了。再次,基于此,需要通过目录的链接进入每个文章的页面,提取标题、文字和时间。

  通过bs4函数工具和正则表达式,可以将链接内容提取出来存储在Linklist中。

  点击链接跳转,可以发现内容页面是静态加载的。这时候可以通过get或者post方法获取文章的内容。我这里还是用之前封装好的post方法。

  分别提取文章标题、内容和时间,并将它们存储在title_list、content_list和time_list中。

  5、寻找自动翻页的模式

  通过以上操作,可以得到一次加载的内容,即三页内容(27条新闻),下面会通过寻找模式多次加载。

  寻找模式:

  第 1-3 页:

  第 4-6 页:

  255 页(最后一页):

  发现只更改了startrecord(起始页)和endrecord(结束页)

  所以设置起始页为i=1,结束页为i+26,每次遍历i+27,直到返回的Linklist为空,跳出循环。

  完整代码

  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': 'http://jnsafety.jinan.gov.cn/',

# '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)

return data

# 获取一页中的所有链接

def get_link_list(soup):

# 使用正则表达式提取链接内容

p = re.compile(r'(.*?)?', 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 = item.text

# print(text_content)

# 以标题名作为文件名,防止某些标题含有特殊符号,将其替换为空

sets = ['/', '\\', ':', '*', '?', '"', '', '|']

for char in title:

if char in sets:

title = title.replace(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")

''' 滚动预警

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)

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 = 'http://jnsafety.jinan.gov.cn/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_title_list.extend(title_list)

tol_content_list.extend(content_list)

tol_time_list.extend(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、建立新连接失败:[WinError 10060]连接尝试失败,因为连接方一段时间后没有正确回复或连接的主机没有响应。'))

  问题分析:错误可能是ip被封或者爬虫访问速度太快,服务器来不及响应。

  解决方法:每次gethtml都加time.sleep(1),这样每次爬取的间隔为1秒。如果还是报错,尝试使用代理ip。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线