本文用到了python语言,selenium包爬取并解析网页数据,由于网页上数据是以图片形式呈现,所以还需要用到百度表格识别API去讲图片转文字,最终整理获得共728条土地交易数据。
数据源来自苏州市自然资源和规划局下的土地市场成交公示,我们先来分析下网页结构。由于采用动态加载的方式,很难自己找到请求的url去获取每页的数据,于是采用selenium+Chrome Driver控制浏览器翻页,定义一个函数**get_href()**获取每个公告的网址和标题。代码如下:
注意:1,selenium查找元素返回的是一个element类。
2,element只会查找页面中符合条件的第一个节点 elements查找多个元素,是多个element对象组成的列表。
所以我们获取网页数据分为两个步骤:
1.步骤一,以下都返回的element元素
find_elements_by_xpath()
find_element_by_xpath()
2.步骤二,获取值
elemnt.get_attribute(‘href’)
get_attribute(‘src’)
get_attribute(‘text’)
import time
import pandas as pd
import requests
import os # 创建一个文件夹
# driver地址
driver = webdriver.Chrome() # 可填入 executable_path=r'path'
# header信息
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'}
def get_href(driver,href_lst): WebDriverWait(driver,10).until(EC.visibility_of(driver.find_element_by_xpath("//td[@colspan='2']"))) # 等到元素都加载出来了再执行操作
elements = driver.find_elements_by_xpath("//tr/td[@class='nlist']/a") # 用的selenium找到交易标题位置锁在的所有元素
for e in elements:
ell = e.get_attribute('href') # 其中的网页地址
href_lst.append(ell) #追加到储存网页的列表中
return href_lst;driver
nextpage_button = driver.find_elements_by_xpath("//td//a")[-2]
nextpage_button.click() # 模拟点击下一页
url_lst = list(set(href_lst)) # 去重 追加列表
def getdate(driver,url_lst):
for url in url_lst:
driver.get(url)
# wait = WebDriverWait(driver,5)
# wait.until(EC.visibility_of_all_elements_located(driver.find_element_by_xpath("//tr/td/div"))) # 等到元素都加载出来了再判定 目前会出错
print('正在判断是图片还是表格,网页地址是' + url )
# 判断数据是图片还是表格
lst = []
lst = driver.find_elements(By.CLASS_NAME,'ke-insertfile')
for i in lst:
print(i.get_attribute('href'))
print(len(lst))
if len(lst) == int(0):
print(url+"需要提取img")
get_img(driver,url,header)
else:
print(url+"需要提取xls")
tabledownlodbotton = driver.find_element(By.CLASS_NAME,'ke-insertfile')
print(tabledownlodbotton.get_attribute("text"))
print(tabledownlodbotton.get_attribute("href"))
tabledownlodbotton.click()
print("xls下载中")
下载地址:(苏州市土地交易img.zip: https://url14.ctfile.com/f/15696614-730302242-d0eec0?p=2304 (访问密码: 2304)
文件密码: Ing_ideas
下载地址:(所有网站的网址和标题.zip: https://url14.ctfile.com/f/15696614-730303826-6f7eec?p=2304 (访问密码: 2304)
文件密码: Ing_ideas
找了半天发现百度智慧云有表格图片识别转文字的功能,并且每天能调用200次:
百度智慧云的token和百度地图的不一样,需要调用接口生成token,方法见文档。
pythonfiles_list = os.listdir(img_floder) # 得到文件夹下的所有文件名称,存在字符串列表中
for img_title in files_list:
img_dir = img_floder +"/" + img_title
# 二进制方式打开图片文件
f = open(img_dir, 'rb')
img = base64.b64encode(f.read()) # base64编码urlencode后大小不超过4M,最短边至少15px,最长边最大4096px
request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/form"
params = {"image": img}
access_token = access_token # '[调用鉴权接口获取的token]'
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/x-www-form-urlencoded'}
response = requests.post(request_url, data=params, headers=headers)
if response:
data = response.json()
try:
if data != '':
get_json(data, img_title) # 后面构造储存json文件的函数
print('识别完成')
# time.sleep(1)
except:
print('识别错误')
返回的文件格式如下,需要想办法保存:
{
"result": {
"result_data":"{
"form_num": 1,
"forms": [
{
"footer": [],
"header": [
{
"column": [
1,
2
],
"probability":0.925165,
"rect":{"left":1138.0,"top":127.0},
"row": [
1
],
"word": "表头信息1",
}
],
"body": [
{
"column": [
1,
2
],
"probability":0.999275,
"rect":{"left":171.0,"top":26.0},
"row": [
1
],
"word": "单元格文字",
}
],
}
]
}
}
可以看到数据在json文件['forms_result'][0]['header'])
中。
主要用到了pandas包,用显示索引loc指定row\column的值为word:
result_df.loc[result_json['row'], result_json['column']] = result_json['words']
因为存在表头header和表尾部footer,如果存在数据就需要判断我们所要的值,不然会丢失数据:
def get_json(data,img_title):
print(data)
result_df = pd.DataFrame()
if len(data['forms_result'][0]['header']) == 0:
print('header为空')
for result_json in data['forms_result'][0]['body']:
result_df.loc[result_json['row'], result_json['column']] = result_json['words']
print(result_df)
print(img_title)
pattern = re.compile("\d{22,}\w\d{1,4}")
json_title = re.findall(pattern, img_title)[0]
print(json_title)
result_df.to_json('E:/Python_on_E/OCR shibie/data2/{}.json'.format(json_title))
print('保存成功')
if len(data['forms_result'][0]['header']) != 0:
print('header不为空 存在标题')
for result_json in data['forms_result'][0]['header']:
result_df.loc[result_json['row'], result_json['column']] = result_json['words']
for result_json in data['forms_result'][0]['body']:
result_df.loc[result_json['row']+1, result_json['column']] = result_json['words']
print(result_df)
#
pattern = re.compile('\d{22,}\w\d{1,4}')
json_title = re.findall(pattern, img_title)[0]
result_df.to_json('E:/Python_on_E/OCR shibie/data2/{}.json'.format(json_title))
print('保存成功')
主要用到如下代码:
df_tmp.dropna(inplace=True,how='all') # 将全部项都是nan的row删除)
row_count = int(len(df_tmp.columns))
df_tmp.replace(r'\n','', inplace = True, regex=True)
df_tmp.replace(r'序\\n号', '序号', inplace=True, regex=True)
df_tmp.replace('度', '序号', inplace=True)
df_tmp.replace(['她地位管','地块位算'], '地块位置', inplace=True)
df_tmp.replace('密得单位', '竞得单位', inplace=True)
第一次学爬虫,还是有点成就感的,欢迎关注和点赞收藏,后续会分析更多数据分析的内容。