梦想橡皮擦,一个逗趣的互联网高级网虫。
又到每年的 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")
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
获取到的数据存储格式如下,以 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 threading
import requests as r
from queue import Queue
import time
from lxml import etree
import json
CRAWL_EXIT = False
PARSE_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)
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()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
本次数据获取,为了不让你那么容易就找到哪个商铺价钱便宜,我专门存储成了
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 照片,一直在给橡皮擦暴击。
写在后面
为了方便大家学习源码,我上传了一个收费源码:
https://download.csdn.net/download/hihell/15222145
,哈哈哈,如果你不想购买,添加橡皮擦微信索取吧。
相关阅读
技术专栏
-
Python 爬虫 100 例教程,超棒的爬虫教程,立即订阅吧
-
Python 爬虫小课,精彩 9 讲
今天是持续写作的第
79
/ 100 天。
如果你有想要交流的想法、技术,欢迎在评论区留言。
如果你想跟博主建立亲密关系,可以关注博主公众号 “
非本科程序员
”,了解非本科程序员是如何成长。
博主 ID:
梦想橡皮擦
,希望大家点赞、评论、收藏。