excel抓取网页动态数据( 爬取代码解析需要的包有numpypandas,,等代码)
优采云 发布时间: 2022-04-04 22:08excel抓取网页动态数据(
爬取代码解析需要的包有numpypandas,,等代码)
标签位置明确了,说下爬取的基本思路:
先获取30条记录的链接,然后依次爬取信息,最后打开下一页,重复。
这是第一次爬取(有100页),一旦出现异常,可以先保存爬取的。
二、代码分析
需要的包有numpy、pandas、BeautifulSoup、re、urllib等。
代码分析如下:
1、getbsobj 函数
def getbsobj(url):
try:
html = urlopen(url,timeout=3)
except (HTTPError,socket.timeout):
return None
return BeautifulSoup(html,'html.parser')
定义一个返回 bs 对象的函数,包括一些异常处理。
2、getLinksList 函数
def getLinksList(url,n):
'''
:param url: 链接
:param n: 第n页
:return: 链接列表
'''
ls = []
bsobj=getbsobj(url+'/pg%d'%n)
if not bsobj:
print('该页打不开')
return None
while True:
aTagList = bsobj.find('ul', {'class': 'listContent'}).findAll('a', {'class': 'img'})
if len(aTagList)>0:
print('打开成功')
break
else:
print('进入休眠')
time.sleep(60)
bsobj=getbsobj(url+'/pg%d'%n)
for aTag in aTagList:
if 'href' in aTag.attrs:
ls.append(aTag['href'])
return ls
定义函数获取30条交易记录链接,并以列表的形式返回。
该链接位于 ul 标签下的 a 标签中。
中间有个圈。原因是有时候网页可以打开,但是交易记录没有显示。这时候需要再次尝试打开,直到出现交易记录。如果没有开启,可能是因为访问过于频繁,所以在无法开启的时候,会进入休眠60秒。
3、getInfo 函数
infoArray = []
一条记录的信息是通过一维列表保存的,infoArray是一个二维列表,保存了所有获取到的记录的信息。
tags = bsobj.find('div',{'class':'introContent'}).findAll('li')
获取收录基本属性和事务属性内容的标记列表。
info = list()
info.append(bsobj.head.title.get_text().split()[0])
info 是保存记录的所有信息的临时列表。
此处添加的是社区名称。
for tag in tags:
info.append(tag.get_text().strip()[4:])
这里添加的是基础属性和交易属性的内容
ul = bsobj.find('ul',{'class':'record_list'})
info.append(ul.li.span.get_text().strip())
text = ul.li.p.get_text().strip()
a = re.search(r'\d+元/平',text)
if a ==None:
info.append('无')
else:
info.append(a.group()[:-3])
b = re.search(r'\d+-\d+-\d+', text)
if b == None:
info.append(text)
else:
info.append(b.group())
这里添加的是交易金额、单价和交易日期,因为和上面的属性不一样,需要单独处理。
infoArray.append(info)
添加记录
arr = np.array(infoArray)
将最终的 infoArray 转换为矩阵 arr 并返回它。
4、checkid 函数
检查动态爬取时是否获取到id。如果已经获取到,则说明上次运行的最新记录已经被爬取,此时无需继续爬取。
def checkid(ls,id):
'''
:param ls: 链接列表
:param id: 成交id
:return: bool
'''
links = []
tag = False
for lk in ls:
if lk[-17:-5]!=str(id):
links.append(lk)
else:break
if len(links)!=len(ls):
tag = True
ls = links
return tag,ls
在这里,检查列表中的每个链接。如果 id 与上次保存的 id 相同,则该链接及其后续链接都被丢弃,并返回一个 bool 值和一个已处理的列表。
5、getIndex 函数
用于获取保存到 Excel 时所需的属性标签
def getIndex(url):
cols = ['小区名字']
ls = getLinksList(url, 1)
bs = getbsobj(ls[0])
tags = bs.find('div', {'class': 'introContent'}).findAll('li')
for tag in tags:
cols.append(tag.span.get_text().strip())
cols += ['成交额(万元)','单价(元/平)','日期']
new_id = ls[0][-17:-5]
return cols,new_id
6、下载功能
主功能
def download(url,start,end):
从起始页开始,爬到结束页(包括结束页)
cols,new_id = getIndex(url)
获取最新记录的属性列表和id号
ls = getLinksList(url,i)
获取链接列表
tag,ls = checkid(ls,id)
检查*敏*感*词*
arr=getInfo(ls)
获取数据矩阵
df_new = pd.DataFrame(arr,columns=cols)
df = df.append(df_new,ignore_index=True)
转换为 DataFrame 格式。
df_old = pd.read_excel('链家成交数据.xlsx')
df_old = df.append(df_old, ignore_index=True)
df_old.to_excel('链家成交数据.xlsx')
另存为 Excel。
三、输出结果
四、完整代码
from bs4 import BeautifulSoup
from urllib.request import urlopen
from urllib.error import HTTPError
import pandas as pd
import numpy as np
import re
import socket,time
url = 'https://bj.lianjia.com/chengjiao'
def getbsobj(url):
try:
html = urlopen(url,timeout=3)
except (HTTPError,socket.timeout):
return None
return BeautifulSoup(html,'html.parser')
def getLinksList(url,n):
'''
:param url: 链接
:param n: 第n页
:return: 链接列表
'''
ls = []
bsobj=getbsobj(url+'/pg%d'%n)
if not bsobj:
print('该页打不开')
return None
while True:
aTagList = bsobj.find('ul', {'class': 'listContent'}).findAll('a', {'class': 'img'})
if len(aTagList)>0:
print('打开成功')
break
else:
print('进入休眠')
time.sleep(60)
bsobj=getbsobj(url+'/pg%d'%n)
for aTag in aTagList:
if 'href' in aTag.attrs:
ls.append(aTag['href'])
return ls
def getInfo(ls):
'''
:param ls:链接列表
:return: 数组
'''
infoArray = []
i = 1
for lk in ls:
print('正在获取第%d条信息'%i)
bsobj = getbsobj(lk)
if not bsobj:continue
tags = bsobj.find('div',{'class':'introContent'}).findAll('li')
info = list()
info.append(bsobj.head.title.get_text().split()[0])
for tag in tags:
info.append(tag.get_text().strip()[4:])
ul = bsobj.find('ul',{'class':'record_list'})
info.append(ul.li.span.get_text().strip())
text = ul.li.p.get_text().strip()
a = re.search(r'\d+元/平',text)
if a ==None:
info.append('无')
else:
info.append(a.group()[:-3])
b = re.search(r'\d+-\d+-\d+', text)
if b == None:
info.append(text)
else:
info.append(b.group())
infoArray.append(info)
i += 1
print('-'*20)
arr = np.array(infoArray)
return arr
def checkid(ls,id):
'''
:param ls: 链接列表
:param id: 成交id
:return: bool
'''
links = []
tag = False
for lk in ls:
if lk[-17:-5]!=str(id):
links.append(lk)
else:break
if len(links)!=len(ls):
tag = True
ls = links
return tag,ls
def getIndex(url):
cols = ['小区名字']
ls = getLinksList(url, 1)
bs = getbsobj(ls[0])
tags = bs.find('div', {'class': 'introContent'}).findAll('li')
for tag in tags:
cols.append(tag.span.get_text().strip())
cols += ['成交额(万元)','单价(元/平)','日期']
new_id = ls[0][-17:-5]
return cols,new_id
def download(url,start,end):
i = start
fn = open('id.txt','r')
id = fn.readline()
fn.close()
cols,new_id = getIndex(url)
df = pd.DataFrame()
try:
while True:
print('正在获取第%d页链接'%i)
ls = getLinksList(url,i)
if not ls:
print(ls)
print(1)
break
#print(ls)
tag,ls = checkid(ls,id)
#print(ls)
arr=getInfo(ls)
df_new = pd.DataFrame(arr,columns=cols)
df = df.append(df_new,ignore_index=True)
if tag:
print(2)
break
i += 1
if i>end:
print(3)
break
except Exception as e:
print(e)
else:
df_old = pd.read_excel('链家成交数据.xlsx')
df_old = df.append(df_old, ignore_index=True)
df_old.to_excel('链家成交数据.xlsx')
fn = open('id.txt', 'w')
fn.write(new_id)
fn.close()
print('程序执行完毕!')
if __name__ == '__main__':
download(url,1,20)
第一次爬取时,需要对上面的代码稍作修改,在try后面加一个finally,保存爬取的内容,防止异常造成的丢失。以上代码可用于后续爬取。据观察,链家数据每天更新3到16页,所以下载功能的参数取1和20。
正常结束应该是先打印(2),再打印(程序执行完毕),如果一天更新21页,则先打印(3),再打印(程序执行完毕)完成),那么就需要修改参数再执行,当然也可以直接把参数20改成100,这样除非出现莫名其妙的异常,一般都能正常执行。