新手,整个程序还有不少瑕疵。json
1.房源访问的网址为城市的拼音+后面统一的地址。须要用到xpinyin库app
2.用了2种解析网页数据的库bs4和xpath(先学习的bs4,学了xpath后部分代码改为xpath)ide
遇到的问题:学习
1.在解析页面时,鼠标点击过位置的div的class属性值有变化,没有注意,致使浪费很长时间。下图,点击后的div的class属性值的空格没有了。url
2.基础学习还要增强,字符串和列表基本命令和转换使用不熟练。
spa
3.没有真正理解 new_list = [i for i in list if i != ''] #删除列表里的空值 这条语句的意思,只是照搬过来用。
code
import urllib.request import urllib.parse from bs4 import BeautifulSoup from xpinyin import Pinyin import time from lxml import etree import json class anjuk_spider(object): url = '.fang.anjuke.com/loupan/all/'
def __init__(self,city): self.city = city #建一个空列表,存放全部的房源信息
self.items = [] #把输入的城市转换成拼音
def citypinyin(self,city): p = Pinyin() return p.get_pinyin(self.city,'') #构建请求体
def handle_request(self,city_url,page_num): city_url = city_url + 'p' + str(page_num + 1) + '/' headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36" } request = urllib.request.Request(city_url, headers=headers) return request #解析价格
def price(self,item): temp = item.xpath('.//a[@class="favor-pos"]/p[1]/text()')[0] if temp == '售价待定': temp = temp + " 周边均价:" + item.xpath('.//a[@class="favor-pos"]/p/span/text()')[0] + "元/㎡"
else: temp = temp + item.xpath('.//a[@class="favor-pos"]/p/span/text()')[0] + "元/㎡"
return temp #解析户型
def huxing(self,item): temp = item.xpath('.//a[@class="huxing"]//text()') # 第1步,先创建个空列表。整理爬下来的列表,去掉空格,换行等
list = [] for item in temp: item = item.replace("\n", "").replace("\t", "").replace("\xa0", "").replace("/", "").replace(" ", "") list.append(item) # 删除列表里的空值
new_list = [i for i in list if i != ''] # 把整理好的列表转换成新字符串
item_huxing = "/".join(new_list) return item_huxing #解析位置
def address(self,item): temp = item.xpath('.//a[@class="address"]//span[@class="list-map"]/text()')[0] end_item_address = temp.find("]") item_address = temp[end_item_address + 2:] return item_address #解析数据
def parse_content(self,content): #利用xpath提取数据
tree = etree.HTML(content) div_list = tree.xpath('//div[@class="key-list imglazyload"]//div[@class="item-mod "]') for item in div_list: try: #小区名称
item_name = item.xpath('.//h3//span[@class="items-name"]/text()')[0] #小区位置
item_address = self.address(item) #小区户型
item_huxing = self.huxing(item) # 小区价格
item_Price = self.price(item) #把数据存放到字典中
dict = { "小区名称":item_name, "小区位置":item_address, "户型面积":item_huxing, "价格":item_Price, } #每条字典更新到列表中
self.items.append(dict) print("小区名称:%s | 位置:%s" %(item_name,item_address)) print("%s|价格:%s" %(item_huxing,item_Price)) print("******************************************************************************") time.sleep(1) # print("小区名称:%s | 小区位置:%s |价格:%s" % (item_name,item_address,item_Price))
except: print("读取出现问题!") def run(self): # 先要取得请求网址,请求网址的组合为城市拼音+上后面的网址
citypinyin = self.citypinyin(self.city) #输入的城市请求网址
city_url = 'https://' + citypinyin + self.url headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36" } #请求体
city_request = urllib.request.Request(city_url,headers = headers) # 发送请求
content = urllib.request.urlopen(city_request).read().decode() #处理响应数据,提取当前房源数量,判断应读取几页数据
#建立bs4对象
soup = BeautifulSoup(content,'lxml') temp_page = int(soup.select('.list-results > .key-sort > .sort-condi > span > em')[0].text) #用取得的房源数量,计算须要读取多少页数据
#每页有60条数据,若是能整除,那就有总数/60页,若是不能整除,那么就总数/60取整+1页。
if temp_page <= 60: page = 1
if (temp_page % 60) == 0: page = temp_page / 60
else: page = (temp_page // 60) + 1
#发送请求
for page_num in range(page): #输入网址,页数,反回请求数据
request = self.handle_request(city_url,page_num) content = urllib.request.urlopen(request).read().decode() #解析数据
self.parse_content(content) time.sleep(2) #转成json格式
string = json.dumps(self.items,ensure_ascii=False) #将数据写入文本中
with open('安居客房价.txt','w',encoding='utf-8') as f: f.write(string) print("存入文本!") def main(): city = input("请输入城市名字:") #建立对象,开始爬取数据
spider = anjuk_spider(city) spider.run() if __name__ == '__main__': main()