Python网络爬虫实战

一、简介

用途:此程序为爬取链家各城市楼盘信息并存入csv文件中
环境:pthon3
库:requests、re、bs4、pandas
链家新房楼盘网址:https://sh.fang.lianjia.com/loupan/

二、思路及流程

  • 目标:
    爬取各个地区的:楼盘名称、地理位置、均价
  • 目标定位分析:
    1.观察发现每个楼盘信息都存放于标签li中()
    2.标签a存放了楼盘名及具体地址(用属性class和href定位)
    3.标签span存放了地点信息及价格信息!
  • 链接变换分析:
  1. 地区变化:
    上海:https://sh.fang.lianjia.com/loupan/
    合肥:https://hf.fang.lianjia.com/loupan/
    地区首字母缩写控制地区变化
  2. 单个地区内翻页变化(上海为例)
    第一页: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.png
    image.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#若某个楼盘解析失败,使循环能继续

目标定位:

  1. 楼盘名定位特征(上海vs合肥)

    楼盘名1.png
    image.png

    2.地理位置定位特征

    地点.png

    3.价格定位特征

    价格.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)

相关推荐

    Database error: [You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1]

    select ID from ac_posts where ziID =  ;