week1_实战作业

说明

作业并不是完全按照老师的要求实现的,一方面是因为58同城改版后很少有普通商品,另一方面是想多做一些基础语法的练习,但整体上还是抓取网页并解析商品信息的思路。
程序当中注释比较多,这里就不在整体描述编程思路。

代码

#coding=utf-8

'''提取58同城二手市场中的板块商品信息(包括格式严格的推广和转转商品,以及格式不规范的普通商品(粗粒度)),按照板块保存到本地文件'''
from bs4 import BeautifulSoup
import requests,os,time

#############################################################################
def get_block_info(host):
    '''从首页中提取二手市场下板块信息'''

    resp = requests.get(host)
    soup = BeautifulSoup(resp.text,'lxml')

    #二手市场下分类板块,如果使用' div > div > em > a' 路径的话可以提取所有二级板块信息
    blocks  = soup.select(' div.fl.cbp2.cbhg > div > em > a')

    #存放二手市场下区块的列表,每个区块为一个字典
    blocklist = []
    for block in blocks:
        href = block['href']
        if href.startswith('/') and href.endswith('/'):
            href = href.split('/')[1]
            data ={
                'name' : block.string,  #区块中文名称
                'block' : href,         #区块命名
                'block_url' : host+href #拼接区块url
            }
            blocklist.append(data)
    return blocklist

#############################################################################
def get_goods_infos(pageurl):
    '''传入一个列表页面url,提取页面当中所有商品信息
    由于转转,推广商品的信息格式规范,可以分类提取
    普通商品格式不一致,无法详细提取各类信息,且会和转转,推广商品重复,故这里只有在获取不到以上两类商品时,按粗粒度获取所有商品信息'''
    resp = requests.get(pageurl)
    soup = BeautifulSoup(resp.text, 'lxml')
    time.sleep(1)  # 停顿一秒,降低访问频率

    #一个存储区块单个页面商品信息的数据结构:{[推广商品信息列表],[转转商品信息列表],{前两者获取不到时获取所有商品信息}}
    info_of_single_page = {}

    #获取正规格式的推广商品信息
    jz_infos = []  # 存储单个页面推广商品信息的列表
    jz_titles = soup.select(' tr.jztr > td.t > a.t')
    jz_times = soup.select('tr.jztr > td.t > span.fl')
    jz_prices = soup.select('tr.jztr > td.tc > b')
    jz_descs = soup.select('tr.jztr > td.t > span.red_adinfo')
    jz_areas = soup.select(' tr.jztr > td.t > span.fl > a')
    for jz_title,jz_time,jz_price,jz_desc,jz_area in zip(jz_titles,jz_times,jz_prices,jz_descs,jz_areas):
        jzdata = {  #单条推广商品信息字典
            '商品名称' : jz_title.get_text(),
            '商品链接': jz_title.get('href'),
            '发布时间' : jz_time.get_text().split('/')[1].strip(),
            '价格' : jz_price.get_text(),
            '描述' : jz_desc.get_text(),
            '区域' : jz_area.get_text()
        }
        jz_infos.append(jzdata)
    info_of_single_page['jzgoods'] = jz_infos

    #获取正规格式的转转商品信息
    zz_infos = []  # 存储单个页面转转商品信息的列表
    zz_titles = soup.select(' tr.zzinfo > td.t > a.t')
    zz_prices = soup.select(' tr.zzinfo > td.t > span.pricebiao > span')
    zz_descs = soup.select(' tr.zzinfo > td.t > span.desc')
    zz_areas = soup.select(' tr.zzinfo > td.t > span.fl ')
    zz_posters = soup.select('tr.zzinfo > td.tc > div > p:nth-of-type(2)')
    for zz_title,  zz_price, zz_desc, zz_area,zz_poster in zip(zz_titles, zz_prices, zz_descs, zz_areas,zz_posters):
        zzdata = {  #单条转转商品信息字典
            '商品名称': zz_title.get_text(),
            '商品链接': zz_title.get('href'),
            '价格': zz_price.get_text(),
            '描述': zz_desc.get_text(),
            '区域': ''.join(list(zz_area.stripped_strings)),
            '发布者' : zz_poster.get_text()
        }
        zz_infos.append(zzdata)
    info_of_single_page['zzgoods'] = zz_infos

    #由于部分板块记录格式不规范,无法区分推广和转转商品,故在以上两个列表未获取数据时,使用粗粒度获取记录普通商品信息
    goods_infos = []
    if len(jz_infos) == 0 and len(zz_infos) == 0:
        titles = soup.select(' tr > td.t > a.t')
        prices = soup.select(' b.pri')
        for title,price in zip(titles,prices):
            data ={
                '商品名称' : title.get_text(),
                '商品链接' : title.get('href'),
                '商品价格' : price.string
            }
            goods_infos.append(data)
    info_of_single_page['goods'] = goods_infos

    return info_of_single_page  #返回存放商品信息的列表

#############################################################################
def save_goods_infos2files(filepath,goodsinfolist):
    '''传入一个文件名及一个列表,将商品信息按照区块创建不同文件续写到对应文件中
    filepath为要创建的文件路径
    goodsinfo是单个页面获取到的商品信息列表'''

    #列表为空则跳出函数(部分页面没有推广信息)
    if len(goodsinfolist) == 0:
        return

    #如果没有区块目录则创建之
    blockpath = os.path.split(filepath)[0]
    if not os.path.exists(blockpath):
        os.makedirs(blockpath)

    #创建商品文件并写入数据
    with open(filepath,'a',encoding='utf-8') as f:
        for item in goodsinfolist:
            f.write(str(item)+'\n')


#############################################################################
if __name__ == '__main__':
    host = 'http://bj.58.com/'
    blocklist = get_block_info(host)
    for block in blocklist:
        #由于58同城只给用户访问前70页的内容,因此这里生成70个页面的url进行访问(测试程序可将可访问页数设小一些)
        invaid_page_num = 5
        for pageurl in [block['block_url']+'/pn{}'.format(str(idx + 1)) for idx in range(invaid_page_num)]:
            #解析每个页面的商品信息
            info = get_goods_infos(pageurl)
            for k,v in info.items():
                filepath = './{}/{}.txt'.format(block['name'], k)
                #讲每个页面的商品信息分类续写到对应目录及文件中
                save_goods_infos2files(filepath, v)

执行结果

Paste_Image.png
Paste_Image.png

小结

1.css path是否是全路径没有关系,只要能唯一定位目标tag即可。-done
2.当前的网页信息获取属于定制模板,网站稍作改版或者被解析数据项不规范即会造成解析失败,有没有更加通用的解析方式?-learning
a.通用解析可能只适用于粗粒度信息获取,譬如网页标题,文本等?
b.想要获取精细结构化数据必须得针对网站进行模板解析?
ps:以上问题后续学习继续探索
3.编码中变量命名要简单明了,格式统一,目前这点做的不好,很多变量名称指示性不强,且格式不太统一,后续编码要注意。-learning
4.关于函数的设置,要注意通用性,切忌为了将代码划分为多个函数而设计出只有当前需求可以使用函数。故函数的参数要尽量是基本数据类型。-learning
5.pycharm代码直接拷贝到简书编辑器时,由于换行编码不一样,不会显示换行。可以使用其他文本编辑器中转一下,譬如notepad。-done
6.BeautifulSoup集中解析模式的异同需要花时间看看。-leaning
7.<class 'bs4.BeautifulSoup'>,<class 'bs4.element.Tag'>,<class 'bs4.element.NavigableString'>三种类之间的关系还需要厘清,包括类的方法及属性。-learning

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 运行结果: 代码: 项目代码 小结 获取内容 body 和 head 不一定要从 HTML 的 body 中获取,...
    超net阅读 505评论 0 0
  • 人生苦短,我用Python。 起初,这篇文章是打算来写 XPath 的,可是后来一想,我需要的仅是 XPath 的...
    Moscow1147阅读 20,717评论 1 14
  • 1. Beautiful Soup的简介 简单来说,Beautiful Soup是python的一个库,最主要的功...
    随风化作雨阅读 2,257评论 0 2
  • 写字注重积累,不管何时何地,提笔即是积累,每次都认真写好,时间久了不知不觉就好了,练字先练心态,其次才是技法,功到...
    乌龟的慢生活阅读 102评论 0 0
  • 离家不远的地方,有一座小山,山上种满了杏树,每年初春,花开遍野,格外的清爽美丽。山的前面是整个村庄,山的后面是成片...
    莫小道阅读 439评论 0 0