Python网络爬虫实战
一、简介
用途:此程序为爬取链家各城市楼盘信息并存入csv文件中
环境:pthon3
库:requests、re、bs4、pandas
链家新房楼盘网址:https://sh.fang.lianjia.com/loupan/
二、思路及流程
- 目标:
爬取各个地区的:楼盘名称、地理位置、均价 - 目标定位分析:
1.观察发现每个楼盘信息都存放于标签li中()
2.标签a存放了楼盘名及具体地址(用属性class和href定位)
3.标签span存放了地点信息及价格信息! - 链接变换分析:
- 地区变化:
上海:https://sh.fang.lianjia.com/loupan/
合肥:https://hf.fang.lianjia.com/loupan/
地区首字母缩写控制地区变化 - 单个地区内翻页变化(上海为例)
第一页:https://sh.fang.lianjia.com/loupan/
第二页:https://sh.fang.lianjia.com/loupan/pg2/
第三页:https://sh.fang.lianjia.com/loupan/pg3/
以pg+数字控制
目标信息:
image.png
源代码分析
image.png
image.png
image.png
image.png
全部地区url获取
选取上海作为初始链接,获取全部地区image.pngimage.png源代码分析
image.png
- 解析流程:
1.获取所有li标签,方法:soup.find_all('tag',attrs={'key':'value'})
2.获取其中的所有a标签和span标签,并筛选
方法:tag.string()获取标签内容、tag['attrs']获取标签属性的值
三、程序架构及函数实现
架构
def getHTMLText(url):#爬取一个html页面def get_url(start_url, Dict):#从初始链接获取其他城市的url,并存入字典内def parsePage(html, List):#提取每个地区的楼盘信息,并存入列表内(每个地区100页)def writeIn_csv(List, name):#将列表转换并写入csv文件以name名门def Text_progress_bar(JDcount, Zcount):#文本进度条def main():
实现
1. 爬取一个html页面
def getHTMLText(url): headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'} try: r = requests.get(url, headers = headers, timeout = 30) r.raise_for_status()#若返回页面状态码不是200则返回HttpError的异常 #已知获取的页面编码为utf-8编码,定向爬虫取消编码替换以提高效率 #r.encoding = r.apparent_encoding return r.text#返回一个 unicode 型的文本数据 except: print(' --此页爬取失败--') return ''#爬取失败返回空字符串
2. 获取其他城市的url,并存入字典内
def get_url(start_url, Dict):#从初始链接获取其他城市的url html = getHTMLText(start_url) soup = BeautifulSoup(html, 'html.parser') #城市信息存于a标签内,以属性title标签定位。re.compile('房产网')正则表达式 all_city = soup.find_all('a', title=re.compile('房产网')) for city in all_city: name = city.string#城市名(tag.string获取标签的内容) urll = city['href']#链接(tag['attrs']获取属性的值) Dict[name] = urll#存入字典
1.png
3. 提取每个地区的楼盘信息,并存入列表内
def parsePage(html, List):#提取每个地区的楼盘信息(每个地区100页) soup = BeautifulSoup(html, 'html.parser') #print(soup.prettify())美化html页面 #楼盘信息都封装在li标签内(含垃圾数据) cut_tag_li = soup.find_all('li') for li in cut_tag_li: pakege = []#列表-存放每个楼盘信息的载体 try: #提取楼盘名 tag_a = li.find('a', attrs={'class':'resblock-img-wrapper'}) loupan = tag_a['title'] #提取地点 tag_span = li.find_all('span') city = tag_span[2].string#周边 area = tag_span[3].string#城市 #具体地址 tag_a = li.find_all('a', attrs={'href':re.compile('/#around')}) location = tag_a[-1].string #提取价格 price_tag_span = li.find_all('span', attrs={'class':'number'}) price = price_tag_span[-1].string address = city + '\n' + area + '\n' + location #将每个楼盘信息暂存入列表pakege #List..append()方法用于在列表末尾添加一个新的对象,只能接收一个参数 pakege.append(loupan) pakege.append(address) pakege.append(price) #将pakege添加到List List.append(pakege) except: continue#若某个楼盘解析失败,使循环能继续
目标定位:
楼盘名定位特征(上海vs合肥)
楼盘名1.pngimage.png2.地理位置定位特征
地点.png3.价格定位特征
价格.png
4. 将列表转换并写入csv文件
#用pandas库写入csv文件def writeIn_csv(List, name): try: title = ['楼盘', '位置', '价格'] file = pd.DataFrame(columns=title, data=List)#数据有三列对应loupan、adress、price #print(file) file_name = 'C:/Users/dell/Desktop/全国/' + name + '.csv' file.to_csv(file_name, encoding='utf_8_sig')#两个参数文件名(路径)和编码方式 print('%s写入csv文件成功' %(name)) except: print('%s写入csv文件失败' %(name))
pandas写入csv文件理解如图
参考原文:https://blog.csdn.net/weixin_40096730/article/details/81255136
image.png
5. 文本进度条
此文本进度条在总量数字较小时误差较大。。。
#文本进度条def Text_progress_bar(JDcount, Zcount):#参数(进度,总量) lenth = 30 #控制进度条长度,以比例显示进度 a = '*' * int( (JDcount/Zcount) * lenth ) b = '.' * int( lenth - (JDcount/Zcount) * lenth ) print('\r[{}->{}]进度{:.2f}%'.format( a, b, JDcount*100/Zcount ), end='')
6.main()函数
def main(): count = 2 #爬取的城市数 depth = 2 #每个城市爬取页数 JDcount = 0 Dict = {} #存放各城市及其url start_url = 'https://sh.fang.lianjia.com/loupan/#pudong' get_url(start_url, Dict)#从初始链接获取其他城市的url #遍历获取所有城市,count控制数量 for dic in Dict: List = [] #列表-载体-存放每个城市楼盘信息 count -= 1 JDcount += 1 if count < 0:#城市数量<0时跳出 break name = dic#城市名(字典的key) name_url = Dict[dic]#城市url(字典的value) url = 'https:' + name_url + '/loupan/pg'#合成每个城市的url print('{}.正在爬取城市-{}'.format(JDcount, name)) for i in range(depth):#每个城市爬取深度(页面数) Text_progress_bar(i, depth)#进度条 new_url = url + str(i) + '/' html = getHTMLText(new_url) parsePage(html, List) writeIn_csv(List, name)#写入csv文件
四、完整代码
'''此程序为爬取链家各城市楼盘信息分析:1.观察发现每个楼盘信息都存放于标签li中()2.标签a存放了楼盘名及具体地址(用属性class和href定位)3.标签span存放了地点信息及价格信息解析流程:1.获取所有li标签,方法:soup.find_all()2.获取其中的所有a标签和span标签,并筛选'''import requestsimport refrom bs4 import BeautifulSoupimport pandas as pddef getHTMLText(url): headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'} try: r = requests.get(url, headers = headers, timeout = 30) r.raise_for_status() #获取的页面编码为utf-8 ''' print(r.encoding) print(r.apparent_encoding) r.encoding = r.apparent_encoding ''' #print(' --此页爬取成功--') return r.text except: print(' --此页爬取失败--') return ''def get_url(start_url, Dict):#从初始链接获取其他城市的url html = getHTMLText(start_url) soup = BeautifulSoup(html, 'html.parser') all_city = soup.find_all('a', title=re.compile('房产网')) for city in all_city: name = city.string#城市名 urll = city['href']#链接 Dict[name] = urll#存入字典 #print(Dict)def parsePage(html, List):#提取每个地区的楼盘信息(每个地区100页) soup = BeautifulSoup(html, 'html.parser') #print(soup.prettify()) 美化 #楼盘信息都封装在li标签内(有垃圾数据) tag_li = soup.find_all('li') cut_tag_li = tag_li[:] #print(len(tag_li))#389 366-376 #print(len(cut_tag_li)) for li in cut_tag_li: pakege = []#列表-存放每个楼盘信息的载体 try: #提取楼盘名 tag_a = li.find('a', attrs={'class':'resblock-img-wrapper'}) loupan = tag_a['title'] #提取地点 tag_span = li.find_all('span') city = tag_span[2].string#周边 area = tag_span[3].string#城市 #具体地址 tag_a = li.find_all('a', attrs={'href':re.compile('/#around')}) location = tag_a[-1].string #提取价格 price_tag_span = li.find_all('span', attrs={'class':'number'}) price = price_tag_span[-1].string address = city + '\n' + area + '\n' + location #将每个楼盘信息暂存入列表pakege #List..append()方法用于在列表末尾添加一个新的对象,只能接收一个参数 pakege.append(loupan) pakege.append(address) pakege.append(price) #将pakege添加到List List.append(pakege) except: #print('楼盘解析失败') continue #print(List) #用pandas库写入csv文件def writeIn_csv(List, name): try: title = ['楼盘', '位置', '价格'] file = pd.DataFrame(columns=title, data=List)#数据有三列 #print(file) file_name = 'C:/Users/dell/Desktop/全国/' + name + '.csv' file.to_csv(file_name, encoding='utf_8_sig') print('%s写入csv文件成功' %(name)) except: print('%s写入csv文件失败' %(name))#文本进度条def Text_progress_bar(JDcount, Zcount):#参数(进度,总量) lenth = 30 #控制进度条长度,以比例显示进度 a = '*' * int( (JDcount/Zcount) * lenth ) b = '.' * int( lenth - (JDcount/Zcount) * lenth ) print('\r[{}->{}]进度{:.2f}%'.format( a, b, JDcount*100/Zcount ), end='')def main(): count = 2 #爬取的城市数 depth = 2 #每个城市爬取页数 JDcount = 0 Dict = {} #存放各城市及其url start_url = 'https://sh.fang.lianjia.com/loupan/#pudong' get_url(start_url, Dict)#从初始链接获取其他城市的url #遍历获取所有城市,count控制数量 for dic in Dict: List = [] #列表-载体-存放每个城市楼盘信息 count -= 1 JDcount += 1 if count < 0:#城市数量<0时跳出 break name = dic#城市名(字典的key) name_url = Dict[dic]#城市url(字典的value) url = 'https:' + name_url + '/loupan/pg'#合成每个城市的url print('{}.正在爬取城市-{}'.format(JDcount, name)) for i in range(depth):#每个城市爬取深度(页面数) Text_progress_bar(i, depth)#进度条 new_url = url + str(i) + '/' #print('\n正在爬取第{}页:'.format(i+1) + new_url) html = getHTMLText(new_url) parsePage(html, List) writeIn_csv(List, name)#写入csv文件main()
五、运行结果
运行.png
结果.png
image.png
赞 (0)