情人节,你刚表白,而我已经开始选哪里拍婚纱照了~


作者 | 梦想橡皮擦   责编 | 丁恩华

来源 | 来自 CSDN 博客

又到每年的 2 月 14 日了,最近这几天,你肯定会在博客上看到,程序员花式秀恩爱,但橡皮擦就不一样了,正在帮别人选婚纱照拍摄地。

当你 new 出来的对象问你,“北京在哪拍婚纱照便宜又好呀?” 你啪啪啪把数据展示出来,绝对可以赢得你的小可爱那爱恋的眼神。

写在前面

挖掘目的已经确定,下面就是挖掘代码编写的时间了,作为年轻人,好好秀恩爱吧,苦差事就交给我们这些过来人。

这次咱们的目标网站是:https://www.jiehun.com.cn/,遥想当年橡皮擦的婚纱照还是在婚博会上订的呢~

这个组织在每年春夏秋冬四季在北京、上海、广州、天津、武汉、杭州、成都等地同时举办大型结婚展。

目标页面长成下面这个样子。


我们要抓取的就是上面商铺的各种信息,包含商铺名,商铺地址,评星,点评数,价格。

数据抓取过程

在做正式抓取之前,可以先编写一个 demo,对数据进行简单的抓取与解析,具体实现可以参照下文。

其中用到了 XPath 解析,该网站如果不使用 UA 参数,无法获取到数据,也算是一种最简单的反爬手段吧。

def demo():    headers = {        "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36"}    url = f"https://www.jiehun.com.cn/beijing/ch2065/store-p13/?ce=beijing"    content = r.get(url, headers=headers).text    html = etree.HTML(content)    li_list = html.xpath("//div[@id='stlist']/ul/li")    for li in li_list:        # 发现评分        star = li.xpath("./div[@class='comment']/p[1]/b/text()")        comment = "--"        if star:            # 评星            star = star[0]            comment = li.xpath("./div[@class='comment']/p[2]/a/text()")            # 评论            comment = comment[0]        else:            star = "--"
        # 店铺名称        name = li.xpath(".//a[@class='namelimit']/text()")[0]        # 地址        store = li.xpath(            ".//div[@class='storename']/following-sibling::p[1]/text()")[0]        # 价钱        price = li.xpath(            ".//div[@class='storename']/following-sibling::p[2]/span[1]/text()")        if price:            price = li.xpath(                ".//div[@class='storename']/following-sibling::p[2]/span[1]/text()")[0]        else:            price = "--"        item = {            "name": name,            "store": store,            "price": price,            "star": star,            "comment": comment        }        print(item)
        with open("hun.json", "ab+") as filename:            filename.write(json.dumps(                item, ensure_ascii=False).encode("utf-8") + b"\n")

获取到的数据存储格式如下,以 JSON 格式存储,读取的时候每次读取一行即可。

{"name": "9Xi·婚纱摄影", "store": "商家地址:北京市朝阳区朝外大街丙10号9Xi结婚汇购物中心", "price": "¥4999", "star": "--", "comment": "--"}{"name": "非目环球旅拍", "store": "商家地址:杭州市滨江区非目影像(总店)", "price": "¥19800", "star": "--", "comment": "--"}{"name": "小白工作室(私人会所)", "store": "商家地址:朝阳北路天鹅湾北区7号楼二单元502(朝阳大悦城对面)", "price": "--", "star": "--", "comment": "--"}{"name": "朵美婚拍", "store": "商家地址:北京市朝阳区广渠门外大街8号优士阁A座大堂底商", "price": "¥2999", "star": "--", "comment": "--"}{"name": "柏悦时尚艺术馆", "store": "商家地址:立汤路186号龙德广场四层F420A", "price": "--", "star": "--", "comment": "--"}

当测试数据抓取到之后,就可以对全北京的商铺(其他地区的修改对应地址即可)进行批量抓取了,本次数据量虽然不大,但是橡皮擦依旧为你贴心的准备了多线程爬虫(唉~没那么容易学习到爬虫技术)。

以下是完整代码部分,就为了你能获取到最全的数据,一次性的把代码都提供给你了,你的手指可以放在点赞按钮上,为橡皮擦点赞了。

import threadingimport requests as rfrom queue import Queueimport timefrom lxml import etreeimport json
CRAWL_EXIT = FalsePARSE_EXIT = False

class ThreadCrawl(threading.Thread):    def __init__(self, thread_name, page_queue, data_queue):        super(ThreadCrawl, self).__init__()
        self.thread_name = thread_name        self.page_queue = page_queue        self.data_queue = data_queue        self.headers = {            "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36"}
    def run(self):        print("启动", self.thread_name)        while not CRAWL_EXIT:            try:                #                page = self.page_queue.get(False)                url = f"https://www.jiehun.com.cn/beijing/ch2065/store-p{page}/?ce=beijing"
                content = r.get(url, headers=self.headers).text                time.sleep(1)
                self.data_queue.put(content)
            except Exception as e:                print(e)
        print("结束", self.thread_name)

class ThreadParse(threading.Thread):    def __init__(self, thread_name, data_queue, filename, lock):        super(ThreadParse, self).__init__()        self.thread_name = thread_name        self.data_queue = data_queue        self.filename = filename        self.lock = lock
    def run(self):        print("启动", self.thread_name)        while not PARSE_EXIT:            try:                html = self.data_queue.get(False)
                self.parse(html)
            except Exception as e:                print(e)        print("结束", self.thread_name)
    def parse(self, html):        html = etree.HTML(html)
        li_list = html.xpath("//div[@id='stlist']/ul/li")        for li in li_list:            # 发现评分            star = li.xpath("./div[@class='comment']/p[1]/b/text()")            comment = "--"            if star:                # 评星                star = star[0]                comment = li.xpath("./div[@class='comment']/p[2]/a/text()")                # 评论                comment = comment[0]            else:                star = "--"
            # 店铺名称            name = li.xpath(".//a[@class='namelimit']/text()")[0]            # 地址            store = li.xpath(                ".//div[@class='storename']/following-sibling::p[1]/text()")[0]            # 价钱            price = li.xpath(                ".//div[@class='storename']/following-sibling::p[2]/span[1]/text()")            if price:                price = li.xpath(                    ".//div[@class='storename']/following-sibling::p[2]/span[1]/text()")[0]            else:                price = "--"
            item = {                "name": name,                "store": store,                "price": price,                "star": star,                "comment": comment            }
            with self.lock:                self.filename.write(json.dumps(                    item, ensure_ascii=False).encode("utf-8") + b"\n")

def main():    # 页码    page_queue = Queue(14)    for i in range(1, 15):        page_queue.put(i)
    # 数据挖掘结果    data_queue = Queue()    filename = open("hun.json", "ab+")
    # 锁    lock = threading.Lock()
    # 三个挖掘线程    crawl_list = ["挖掘线程1", "挖掘线程2", "挖掘线程3"]
    threadcrawl = []    for thread_name in crawl_list:        thread = ThreadCrawl(thread_name, page_queue, data_queue)        thread.start()        threadcrawl.append(thread)
    # 三个解析线程    parse_list = ["解析线程1", "解析线程2", "解析线程3"]    threadparse = []    for thread_name in parse_list:        thread = ThreadParse(thread_name, data_queue, filename, lock)        thread.start()        threadparse.append(thread)
    # 等待 page_queue 队列为空    while not page_queue.empty():        pass
    global CRAWL_EXIT    CRAWL_EXIT = True
    print("page_queue为空")    for thread in threadcrawl:        thread.join()        print("挖掘队列执行完毕")

    while not data_queue.empty():        pass    global PARSE_EXIT    PARSE_EXIT = True
    for thread in threadparse:        thread.join()        print("解析队列执行完毕")
    with lock:        filename.close()

本次数据获取,为了不让你那么容易就找到哪个商铺价钱便宜,我专门存储成了 JSON 格式,排序的工作就交给你自己来完成了。毕竟你不能有女朋友的同时,一点力也不出吧。

看图选照

你以为这样工作就做完了吗?当然没有,除了价格以外,咱们 new 出来的对象还需要看图选呢,至少要看看谁家拍摄技术高,更符合自己的调调。

接下来,再爬取一个:目标地址

该网站页面数据如下:


要抓取的就是这几千张婚纱摄影照片~

该操作我将其分解成了两个步骤:

  • 第一个步骤批量采集图片详情页的地址;

  • 第二步针对详情页地址,获取图片。

核心部分代码修改如下:

抓取超链接部分,修改 XPath 解析地址即可。

def demo():    headers = {        "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36"}    url = f"https://www.jiehun.com.cn/beijing/ch2065/album-p461/?attr_110=&cate_id=2065&ce=beijing"    content = r.get(url, headers=headers).text    html = etree.HTML(content)    a_list = html.xpath("//div[@class='rectangle_list']/ul/li/a/@href")
    for a in a_list:        with open("album_link.json", "a+") as filename:            filename.write(f"https://www.jiehun.com.cn/{a}\n")


短暂运行一段时间后,得到超链接数据如下:

https://www.jiehun.com.cn//album/730704/https://www.jiehun.com.cn//album/730703/https://www.jiehun.com.cn//album/730702/https://www.jiehun.com.cn//album/730701/https://www.jiehun.com.cn//album/730700/https://www.jiehun.com.cn//album/730699/https://www.jiehun.com.cn//album/730698/https://www.jiehun.com.cn//album/730697/https://www.jiehun.com.cn//album/730696/https://www.jiehun.com.cn//album/730695/https://www.jiehun.com.cn//album/730694/https://www.jiehun.com.cn//album/730693/https://www.jiehun.com.cn//album/730679/
图片抓取,利用 album_link.json 中存储的链接地址,解析对应页面中的 img 标签。
读取 album_link.json 中的数据,生成待抓取链接。
def read_file():    page_queue = Queue()    for f in open("album_link.json","r"):        print(f.strip())        page_queue.put(f)
    print(page_queue.qsize())

提取对应 URL 中的图片地址,并保存。

def demo():    headers = {        "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36"}    url = f"https://www.jiehun.com.cn/album/730698/"    content = r.get(url, headers=headers).text    html = etree.HTML(content)    title = html.xpath("//div[@class='detailintro_l']/h2/text()")[0]    img_list = html.xpath("//div[@class='img']/img/@src")
    for index,img_url in enumerate(img_list):        content = r.get(img_url, headers=headers).content        with open(f"./imgs/{title}-{index}.jpg", "wb+") as filename:            filename.write(content)

编写好完整的代码之后,等着照片存储到本地,就可以给对象一张张的看了,看到好的,在查一下是哪个摄影店,去拍摄就好了。


代码运行一会,就 600+ 照片了,因为硬盘比较小,剩下的大家自己爬取吧

其实是被那一张张狂撒狗粮的照片,喂饱了~,ε=(´ο `*))) 唉,那一张张 KISS 照片,一直在给橡皮擦暴击。

CSDN程序员学院福利来啦

????????

=推荐阅读=

@程序员:爱我你怕了吗

如何一句话“暴击”程序员,网友:哭了!

程序员的爆笑日常,哈哈哈哈

猿趣 | 程序员为什么都爱穿冲锋衣?

点分享

点收藏

点点赞

点在看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值