-->

(项目)爬取自如租房链接的价格

2020-08-08 13:05发布

简介

    假设给定一个自如租房的url,本程序能够实现爬取该网页的价格。经过测试发现,这个程序并不适用于所有的自如租房链接,只适用于大部分链接。(个人认为出现这样的问题与写的规则字符串有关)

① 打开某一个自如租房url。如:http://gz.ziroom.com/x/754308942.html 。打开该链接后,发现右上角显示该商品的价格是2890/月(季付价)。我们的目标是要提取2890这四个价格数字

 

② 打开检查后,观察网页源代码,如下图,分析后得出价格数字2价格数字8价格数字9价格数字0分别对应四个 i 标签,这四个 i 标签分别给出了不同的position,还给出了四个完全一样的图片url

     价格数字2对应的position1为-281.16,价格数字8对应的position2为-156.2,价格数字9对应的position3为-187.44,价格数字0对应的position4为-249.92。

 

 

③ 打开图片url后,得到如下图片。图片上有0-9 十个数字。结合四个价格数字position和在图片上对应的索引(9、5、6、8)-281.16 ÷ 9 = -31.24 ;-156.2 ÷ 5 = -31.24 ; -187.44 ÷ 6 = -31.24 ; -249.92 ÷ 8 = -31.24

  发现position÷索引的值都是-31.24,因此能得到十个数字的position和在图片上对应的索引的关系:从第一个数字5(索引为0,position为0)开始算起,往右的数字中,每当索引增加1,对应的position依次减少31.24。 

  经过计算,可以得到索引从0-9的十个数字在图片上对应的十个position,组成一个position列表:[ 0, -31.24, -62.48, -93.72, -124.96, -156.2,  -187.44, -218.68, -249.92, -281.16 ]

  每次请求页面后,图片url都会随着刷新,得到不一样的图片。得到的每张图片都有十个数字,但在每张图片中数字的排序都不一样。多次请求同一个图片url,得到的图片也是不一样的。多次请求后发现,每次得到的图片上都遵循相邻索引的位置差为31.24。因此我们能够根据position列表和数字的position来确定其在图片上的索引。 

       

 

写代码的思路:

  1 请求网页,得到网页源代码后,通过正则表达式取出需要的信息(四个价格数字的position图片url),并且根据请求到的图片url请求图片。

          注:在封装代码时,要注意获取图片的url根据请求到的图片url来请求该图片这两个操作必须要在同一个函数里,不能分开。也就是不能单独定义一个根据请求到的图片url来请求该图片这个函数。因为多次请求同一个图片url,得到的图片是不一样的。获取图片的url这个操作相当于已经根据图片url请求了这个图片一次,如果再单独定义根据请求到的图片url来请求该图片这个函数的话,当主函数使用这个函数后,相当于重新请求这个图片url。

   ① 为了方便取出四个价格数字的position和图片url,我们可以用正则表达式的分组命名模式来提取。

    (?P<name>...)

    re_object = re.compile(pattern,re.S)

    result = re_object.search(str)

    result.group('name')

   ② 要注意转义匹配,例如要匹配 ( ,可以使用 \(来匹配。

   ③ 本次使用正则表达式时,要注意选取代码的范围,范围可以参考如下图片。

          

  2 把请求到的图片保存到本地。

  3 使用百度的通用文字识别接口来识别下载到本地的图片,得到识别结果(返回的识别结果为0-9十个数字,是str类型)。

  4 用获取到的四个价格数字的positionposition列表进行对比,从而得到每个价格数字在position列表中的索引

   因为用小数对比不方便,所以需要把对比对象都转换为整数。方法是先把数转换为字符串,然后用字符串以'.'符号来分割的方法取整。

   ① 创建一个position列表对应的整数列表

   ② 整数列表使用index方法,依次获取四个取整后的价格数字在整数列表中的索引,这个索引等于在position列表中的索引。

  5 通过每个价格数字的索引把该价格数字从识别结果中取出来。

     取出四个价格数字后,通过字符串的+运算拼接在一起。

 1 #2020-7-3 
2
3 import requests 4 import re 5 6 #获取信息(四个价格数字的位置和图片url),并且请求得到的图片url。返回四个价格数字的位置和请求图片的内容。 7 def get_information(url): 8 #请求一个自如租房的具体链接 9 ziruzufang = requests.get(url) 10 #这个规则字符串使用到分组命名的模式,目的是方便直接提取出想要的分组。(?P<name>) 11 pattern = '<div class="Z_price">.*?<span>¥</span>.*?<i class="num" style="background-position:(?P<position1>.*?)px;background-image: url\((?P<photo_url>.*?)\);" ></i>.*?<i class="num" style="background-position:(?P<position2>.*?)px;background-image: url\((.*?)\);" ></i>.*?<i class="num" style="background-position:(?P<position3>.*?)px;background-image: url\((.*?)\);" ></i>.*?<i class="num" style="background-position:(?P<position4>.*?)px;background-image: url\((.*?)\);" ></i>' 12 #用compile方法生成一个正则表达式对象,使用的模式是re.S 13 re_object = re.compile(pattern,re.S) 14 #用search方法按照规则字符串对整个待扫描的字符串进行扫描 15 information = re_object.search(ziruzufang.text) 16 #把命名为position1、position2、position3、position4的分组提取出来放到jiage_positions空列表里。 17 jiage_positions = [] 18 jiage_positions.append(information.group('position1')) 19 jiage_positions.append(information.group('position2')) 20 jiage_positions.append(information.group('position3')) 21 jiage_positions.append(information.group('position4')) 22 #print(jiage_positions) 23 #把命名为photo_url的分组提取出来与‘http’字符串组成一个完整的图片url路径。 24 photo_url = 'http:' + information.group('photo_url') 25 #对获取到的图片url进行请求 26 photo = requests.get(photo_url) 27 return jiage_positions,photo 28 29 #把请求到的图片下载到本地 30 def save_photo(photo,photo_name): 31 with open(photo_name,'wb') as file: 32 file.write(photo.content) 33 34 #使用百度的通用文字识别接口来识别下载到本地到的图片 35 def get_shibie_result(API_Key,Secret_Key,photo_name): 36 #获取Access Token官方代码,必须要有API Key和Secret Key两个参数才能获取。 37 # client_id 为官网获取的AK, client_secret 为官网获取的SK 38 host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id='+API_Key+'&client_secret='+Secret_Key 39 response = requests.get(host) 40 access_token = response.json()['access_token'] 41 #通用文字识别官方代码 42 import base64 43 request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic" 44 # 二进制方式打开图片文件 45 f = open(photo_name, 'rb') 46 img = base64.b64encode(f.read()) 47 params = {"image":img} 48 access_token = access_token 49 request_url = request_url + "?access_token=" + access_token 50 headers = {'content-type': 'application/x-www-form-urlencoded'} 51 response = requests.post(request_url, data=params, headers=headers) 52 shibie_result = response.json()['words_result'][0]['words'] 53 return shibie_result 54 55 def get_jiage_indexs(jiage_positions): 56 #创建一个整数列表,目的是得到四个价格数字在图片中的索引 57 zhengshu = [] 58 for i in range(10): 59 num = 0 60 num = - (num + (i * 31.24)) 61 zhengshu.append(str(num).split('.')[0]) 62 #print(zhengshu) 63 #对jiage_positions列表进行遍历,每次遍历时,通过zhengshu这个列表和列表的index方法来定位本次价格数字的索引,并且把索引添加到jiage_indexs列表里。 64 jiage_indexs = [] 65 for jiage_position in jiage_positions: 66 jiage_indexs.append(zhengshu.index(jiage_position.split('.')[0])) 67 return jiage_indexs 68 69 def get_jiage(jiage_indexs,shibie_result): 70 #创建一个空字符串,并对价格索引列表进行遍历,通过每次遍历出的索引和图片识别的结果结合,可以得到每次遍历的一个价格数字,通过循环的方式把字符串进行拼接,得到最终的价格。 71 jiage = '' 72 for jiage_index in jiage_indexs: 73 jiage = jiage + shibie_result[jiage_index] 74 print(jiage) 75 76 if __name__ == '__main__': 77 url = 'http://gz.ziroom.com/x/754308942.html' 78 photo_name = 'photo.jpg' 79 infomation = get_information(url) 80 jiage_positions = infomation[0] 81 photo = infomation[1] 82 save_photo(photo,photo_name) 83 shibie_result = get_shibie_result(API_Key=******,Secret_Key=******,photo_name=photo_name) 84 jiage_indexs = get_jiage_indexs(jiage_positions) 85 get_jiage(jiage_indexs,shibie_result)

 

标签: