58同城租房网采用了字体反爬机制,利用字体对页面上的部分数字(如房价、面积平米数)进行了加密处理。
下面的代码包含了爬取房源基本信息并保存为文件的全部代码,在mac下运行有效,windows系统需要参照这里做些必要调整。
以下是抓取房源列表页面并保存为多个html文件,注意更换你的headers内容。
header_str='''
accept: text/html
...
user-agent: Mozilla/5.0
'''
#字符串转dict
def str2dict(s,s1=';',s2='='):
li=s.split(s1)
res={}
for kv in li:
li2=kv.split(s2)
if len(li2)>1:
res[li2[0]]=li2[1]
return res
headers=str2dict(header_str,'\n',': ')
#每页保存为本地html页面待用
import requests
import time
#地址为苏州市
urlstr = 'https://su.58.com/zufang/pn2/?PGTID=0d300008-0000-5965-8ce1-1873463f7758&ClickID={}'
def getPages(n, m):
for i in range(n, m):
print('GETING...', i)
url = urlstr.format(i)
res = requests.get(url, headers=headers)
with open(r'./pages/{}.html'.format(i), 'w') as f:
f.write(res.text)
time.sleep(1)
print('OK!')
getPages(9, 10)
以下是用于破解字体反爬加密的代码。
需要先安装模块,conda install -c mwcraig fonttools
from fontTools.ttLib import TTFont
import base64
import re
import io
def getKey(script):
try:
return re.findall(r"base64,(.*)'\).format", script)[0]
except:
return None
def getFont(key):
data = base64.b64decode(key)
fonts = TTFont(io.BytesIO(data))
return fonts.getBestCmap()
def getDigit(str):
d = re.findall(r'(\d+)', str)[0]
return int(d) - 1
def getRealValue(script, string):
key = getKey(script)
fontMap = getFont(key)
newMap = dict()
#微软雅黑的对应的编码
font58 = {
'閏': '0x958f',
'鸺': '0x9e3a',
'麣': '0x9ea3',
'餼': '0x993c',
'鑶': '0x9476',
'龤': '0x9fa4',
'齤': '0x9f64',
'龥': '0x9fa5',
'龒': '0x9f92',
'驋': '0x9a4b',
}
for key in fontMap.keys():
value = getDigit(fontMap[key])
key = hex(key)
newMap[key] = value
result = ''
for char in string:
temp = font58[char]
value = newMap[temp]
result = '%s%d' % (result, value)
return int(result)
以下是从本地html文件读取数据并解密其中的数字。
from bs4 import BeautifulSoup
import os
files = os.listdir(r'./pages/')
file_li = [r'./pages/' + s for s in files]
items = []
for fp in file_li:
with open(fp, 'r') as f:
html = f.read()
soup = BeautifulSoup(html)
li = soup.find('ul', 'listUl').find_all('li')[:-1]
script = soup.find('head').find_all('script')[-1:]
for item in li:
title = item.find('h2').text.strip()
money = item.find('div', 'money').b.text.strip()
money = getRealValue(script[0].text, money)
roomtag = item.find('p', 'room strongbox')
m2 = roomtag.text.split(' ')[-1:][0].replace('\xa0', '').replace(
'㎡', '')
m2li = m2.split('.')
m2li2 = []
for m in m2li:
m2li2.append(str(getRealValue(script[0].text, m)))
size = '.'.join(m2li2)
items.append(dict(
title=title,
money=money,
size=size,
))
print('OK!')
最后是将items对象写入json文件并测试读取。
import json
with open('items.json', 'w') as f:
f.write(json.dumps(items))
print('Write OK!')
with open('items.json', 'r') as f:
readItems=json.loads(f.read())
print(readItems[10])
print('Read OK!')
每个人的智能新时代
如果您发现文章错误,请不吝留言指正;
如果您觉得有用,请点喜欢;
如果您觉得很有用,欢迎转载~
END