Научно-исследовательский институт домашних животных Мяу

Python
Научно-исследовательский институт домашних животных Мяу

Наггетс недавно запустили "«Сосущие кошки» с кодом", запустивший две душевные пытки:

  • у тебя есть кот?
  • Вы завидуете людям, у которых есть кошки?

Мой ответ: у меня нет кошек, и я не завидую людям, у которых есть кошки. Занятие требует использования кодов для привлечения кошек.Посмотрев это занятие, я обнаружил, что есть довольно много друзей, которые интересуются кошками.Некоторые друзья из группы всегда показывают мне кошек, что вызывает у меня любопытство к кошкам.

Если вы хотите сосать кошку, вы должны сначала купить кошачью ручку? Если вы хотите купить кошку, вы должны хотя бы сначала понять кошек, верно?Как человек, который мало что знает о кошках, сегодня я воспользуюсь этим заданием, чтобы познакомиться со всеми видами домашних кошек.

Здесь я нашел сайт, посвященный торговле кошками — Maomao Trading Network:www.maomijiaoyi.com/

В разделе «Породы кошек» перечислены различные типы домашних кошек:image-20211120115756303Мы можем собирать данные и узнавать о характеристиках различных домашних кошек.

В итоге эта статья имеет следующие результаты:image-20211121005132096.png

Сбор данных

Сначала мы сканируем список ссылок, по которым может сканироваться домашняя страница:

 from lxml import etree
 import requests
 ​
 headers = {
     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36",
 }
 url_base = "http://www.maomijiaoyi.com"
 session = requests.Session()
 ​
 # 访问猫咪品种入口页,获取各品种详情页的链接
 url = url_base+"/index.php?/pinzhongdaquan_5.html"
 res = session.get(url, headers=headers)
 html = etree.HTML(res.text)
 main_data = []
 for a_tag in html.xpath("//div[@class='pinzhong_left']/a"):
     url = url_base+a_tag.xpath("./@href")[0]
     pet_name, pet_price = None, None
     pet_name_tag = a_tag.xpath("./div[@class='pet_name']/text()")
     if pet_name_tag:
         pet_name = pet_name_tag[0].strip()
     pet_price_tag = a_tag.xpath("./div[@class='pet_price']/span/text()")
     if pet_price_tag:
         pet_price = pet_price_tag[0].strip()
     print(pet_name, pet_price, url)
     main_data.append((pet_name, pet_price, url))

Результат печати следующий:

image-20211120153713167

Если я хочу узнать больше о кошках, мне нужно щелкнуть страницу сведений, чтобы увидеть подробные свойства:

image-20211120160204511

Разберите данные этих трех частей отдельно и протестируйте разбор первой ссылки:

 pet_name, pet_price, url = main_data[0]
 res = session.get(url, headers=headers)
 html = etree.HTML(res.text)
 row = {}
 # 解析基本属性
 for text in html.xpath("//div[@class='details']//text()"):
     text = text.strip()
     if not text:
         continue
     if text.endswith(":"):
         key = text[:-1]
     else:
         row[key] = text
 row["参考价格"] = pet_price
 # 解析外观属性
 for shuxing in html.xpath("//div[@class='shuxing']/div"):
     name, v = shuxing.xpath("./div/text()")
     row[name.strip()] = v.strip()
 row["链接"] = url
 # 解析详细说明
 titles = html.xpath(
     "//div[@class='content']/div[@class='property_title']/div/text()")
 property_tags = html.xpath(
     "//div[@class='content']/div[@class='property_list']/div")
 for title, property_tag in zip(titles, property_tags):
     p_texts = []
     for p_tag in property_tag.xpath(".//p|.//div"):
         p_text = "".join([t.strip()
                           for t in p_tag.xpath(".//text()") if t.strip()])
         if p_text:
             p_texts.append(p_text)
     text = "\n".join(p_texts)
     row[title] = text
 row

Видно, что данные первых двух частей разбираются очень плавно:

image-20211120161536882

Для третьей части данных также успешно парсится:

image-20211120162228130

Помимо информации текстового описания, нам также необходимо сохранить изображение. Следующий код анализирует URL-адрес изображения и загружает его:

 img_urls = [
     url_base+url for url in html.xpath("//div[@class='big_img']/img/@src") if url]
 row["图片地址"] = img_urls
 ​
 for i, img_url in enumerate(img_urls, 1):
     with requests.get(img_url) as res:
         imgbytes = res.content
     with open(f"imgs/{pet_name}{i}.jpg","wb") as f:
         f.write(imgbytes)

Вы можете видеть, что несколько изображений были успешно загружены:

image-20211120164613370

Затем мы можем организовать код веб-сайта, сохранить текстовые данные в Excel и сохранить картинку в файл:

 import pandas as pd
 from lxml import etree
 import requests
 ​
 headers = {
     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36",
 }
 url_base = "http://www.maomijiaoyi.com"
 session = requests.Session()
 ​
 # 访问猫咪品种入口页,获取各品种详情页的链接
 url = url_base+"/index.php?/pinzhongdaquan_5.html"
 res = session.get(url, headers=headers)
 html = etree.HTML(res.text)
 main_data = []
 for a_tag in html.xpath("//div[@class='pinzhong_left']/a"):
     url = url_base+a_tag.xpath("./@href")[0]
     pet_name, pet_price = None, None
     pet_name_tag = a_tag.xpath("./div[@class='pet_name']/text()")
     if pet_name_tag:
         pet_name = pet_name_tag[0].strip()
     pet_price_tag = a_tag.xpath("./div[@class='pet_price']/span/text()")
     if pet_price_tag:
         pet_price = pet_price_tag[0].strip()
     main_data.append((pet_name, pet_price, url))
 data = []
 for pet_name, pet_price, url in main_data:
     res = session.get(url, headers=headers)
     html = etree.HTML(res.text)
     row = {}
     # 解析基本属性
     for text in html.xpath("//div[@class='details']//text()"):
         text = text.strip()
         if not text:
             continue
         if text.endswith(":"):
             key = text[:-1]
         else:
             row[key] = text
     row["参考价格"] = pet_price
     # 解析外观属性
     for shuxing in html.xpath("//div[@class='shuxing']/div"):
         name, v = shuxing.xpath("./div/text()")
         row[name.strip()] = v.strip()
     row["链接"] = url
     # 解析详细说明
     titles = html.xpath(
         "//div[@class='content']/div[@class='property_title']/div/text()")
     property_tags = html.xpath(
         "//div[@class='content']/div[@class='property_list']/div")
     for title, property_tag in zip(titles, property_tags):
         p_texts = []
         for p_tag in property_tag.xpath(".//p|.//div"):
             p_text = "".join([t.strip()
                               for t in p_tag.xpath(".//text()") if t.strip()])
             if p_text:
                 p_texts.append(p_text)
         text = "\n".join(p_texts)
         row[title] = text
     img_urls = [
         url_base+url for url in html.xpath("//div[@class='big_img']/img/@src") if url]
     row["图片地址"] = img_urls
     data.append(row)
     for i, img_url in enumerate(img_urls, 1):
         with requests.get(img_url) as res:
             imgbytes = res.content
         with open(f"imgs/{pet_name}{i}.jpg", "wb") as f:
             f.write(imgbytes)
 df = pd.DataFrame(data)
 df.to_excel("猫咪.xlsx", index=False)

Первые несколько столбцов результатов сканирования выглядят следующим образом:

image-20211120170733453

Скачал картинки разных кошек:

image-20211120170913997

С помощью приведенных выше данных Excel мы можем анализировать и обрабатывать:

анализ данных

Сначала прочитайте данные в Excel:

 import pandas as pd
 ​
 df = pd.read_excel("猫咪.xlsx")

Данные наблюдений показали, что многие домашние кошки имеют несколько псевдонимов. Мы можем построить диаграмму отношений, чтобы показать псевдонимы, соответствующие каждой кошке:

 from pyecharts import options as opts
 from pyecharts.charts import Graph
 ​
 links = []
 nodes = []
 nodes.append({"name": "猫", "symbolSize": 10})
 ​
 for name, alias in df[["中文学名", "别名"]].values:
     nodes.append({"name": name, "symbolSize": 10})
     links.append({"source": "猫", "target": name})
     for dest in alias.split(","):
         if name == dest:
             continue
         nodes.append({"name": dest, "symbolSize": 10})
         links.append({"source": name, "target": dest})
 c = (
     Graph(init_opts=opts.InitOpts(width="800px", height="800px"))
     .add("", nodes, links, repulsion=250,
          linestyle_opts=opts.LineStyleOpts(width=0.5, curve=0.3, opacity=0.7))
     .set_global_opts(title_opts=opts.TitleOpts(title="宠物猫的品种"))
 )
 c.render_notebook()

image-20211120194835315

Основное имя можно просмотреть, когда указатель мыши указывает на центральную точку:

image-20211120195835647

Распределение происхождения Pet Cats:

 from pyecharts.charts import Bar
 data = df.原产地.value_counts()
 c = (
     Bar()
     .add_xaxis(data.index.to_list())
     .add_yaxis("", data.values.tolist())
     .set_global_opts(
         xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=15)),
         title_opts=opts.TitleOpts(title="宠物猫原产地分布")
     )
 )
 c.render_notebook()

image-20211120205233268

Это можно увидеть в различных домашних животных, в основном распределенных в Соединенном Королевстве, Соединенных Штатах и ​​Шотландии.

Затем нарисуйте древовидную диаграмму, показывающую страны, в которых распространены кошки каждой породы:

 data = []
 tmp = df.groupby("原产地", as_index=False).agg(
     品种=("中文学名", ",".join), 品种数=("中文学名", "count"))
 for src, dest in tmp.values[:, :2]:
     dests = dest.split(",")
     children = []
     data.append({"value": len(dests), "name": src, "children": children})
     for dest in dests:
         children.append({"name": dest, "value": 1})
 c = (
     TreeMap(init_opts=opts.InitOpts(width='1280px', height='560px'))
     .add("", data,
          levels=[
              opts.TreeMapLevelsOpts(
                  treemap_itemstyle_opts=opts.TreeMapItemStyleOpts(
                      border_color="#555", border_width=1, gap_width=1
                  )
              ),
              opts.TreeMapLevelsOpts(
                  color_saturation=[0.3, 0.6],
                  treemap_itemstyle_opts=opts.TreeMapItemStyleOpts(
                      border_color_saturation=0.7, gap_width=5, border_width=10
                  ),
                  upper_label_opts=opts.LabelOpts(
                      is_show=True, position='insideTopLeft', vertical_align='top'
                  )
              ),
              opts.TreeMapLevelsOpts(
                  color_saturation=[0.3, 0.5],
                  treemap_itemstyle_opts=opts.TreeMapItemStyleOpts(
                      border_color_saturation=0.6, gap_width=1
                  ),
              ),
              opts.TreeMapLevelsOpts(color_saturation=[0.3, 0.5]),
          ])
     .set_global_opts(title_opts=opts.TitleOpts(title="宠物猫原产地分布"))
 )
 c.render_notebook()

image-20211120224628155

Тогда посмотрите на соотношение разновидностей и размеров тела:

 from pyecharts.charts import Pie
 ​
 c = (
     Pie()
     .add(
         "体型",
         df.体型.value_counts().reset_index().values.tolist(),
         radius=["40%", "55%"],
         label_opts=opts.LabelOpts(
             position="outside",
             formatter="{a|{a}}{abg|}\n{hr|}\n {b|{b}: }{c}  {per|{d}%}  ",
             background_color="#eee",
             border_color="#aaa",
             border_width=1,
             border_radius=4,
             rich={
                 "a": {"color": "#999", "lineHeight": 22, "align": "center"},
                 "abg": {
                     "backgroundColor": "#e3e3e3",
                     "width": "100%",
                     "align": "right",
                     "height": 22,
                     "borderRadius": [4, 4, 0, 0],
                 },
                 "hr": {
                     "borderColor": "#aaa",
                     "width": "100%",
                     "borderWidth": 0.5,
                     "height": 0,
                 },
                 "b": {"fontSize": 16, "lineHeight": 33},
                 "per": {
                     "color": "#eee",
                     "backgroundColor": "#334455",
                     "padding": [2, 4],
                     "borderRadius": 2,
                 },
             },
         ),
     )
     .set_global_opts(
         title_opts=opts.TitleOpts(title="品种体型占比"),
     )
 )
 c.render_notebook()

image-20211120231306359

Только один размер кошки считается самым большим, это Рэгдолл. Ниже мы находим самых дешевых и самых дорогих кошек.В настоящее время считается, что самая низкая цена - самая дешевая порода, а самая высокая цена - самая дорогая порода:

 tmp = df.参考价格.str.split("-", expand=True)
 tmp.columns = ["最低价格", "最高价格"]
 tmp.dropna(inplace=True)
 tmp = tmp.astype("int")
 cheap_cat = df.loc[tmp.index[tmp.最低价格 == tmp.最低价格.min()], "中文学名"].to_list()
 costly_cat = df.loc[tmp.index[tmp.最高价格 == tmp.最高价格.max()], "中文学名"].to_list()
 print("最便宜的品种有:", cheap_cat)
 print("最贵的品种有:", costly_cat)
 最便宜的品种有: ['加菲猫', '金渐层', '银渐层', '橘猫']
 最贵的品种有: ['布偶猫', '缅因猫', '无毛猫']

Для ['всего', 'волосы', 'цвет', 'голова', 'глаза', 'уши', 'нос', 'хвост', 'грудь', 'шея', 'предшественник' в наборе данных, ' задний привод'] Все эти столбцы являются описаниями кошек, мы можем объединить их в единое целое, чтобы составить карту облака слов для кошек:

 import stylecloud
 from IPython.display import Image
 text = ""
 for row in df[['整体', '毛发', '颜色', '头部', '眼睛', '耳朵',
                '鼻子', '尾巴', '胸部', '颈部', '前驱', '后驱']].values:
     for v in row:
         if pd.isna(v):
             continue
         text += v
 stylecloud.gen_stylecloud(text,
                           collocations=False,
                           font_path=r'C:\Windows\Fonts\msyhbd.ttc',
                           icon_name='fas fa-cat',
                           output_name='tmp.png')
 Image(filename='tmp.png')

image-20211120234638333

Затем мы делаем карты облаков слов для характеристик личности и жизненных привычек.

Карта облака слов с характеристиками символов:

 import jieba
 import stylecloud
 from IPython.display import Image
 ​
 stopwords = ["主人", "它们", "毛猫", "不会", "性格特点", "猫咪"]
 words = df.性格特点.astype("str").apply(jieba.lcut).explode()
 words = words[words.apply(len) > 1]
 words = [word for word in words if word not in stopwords]
 stylecloud.gen_stylecloud(" ".join(words),
                           collocations=False,
                           font_path=r'C:\Windows\Fonts\msyhbd.ttc',
                           icon_name='fas fa-square',
                           output_name='tmp.png')
 Image(filename='tmp.png')

image-20211121000541560

 import jieba
 import stylecloud
 from IPython.display import Image
 ​
 stopwords = ["主人", "它们", "毛猫", "不会", "性格特点", "猫咪"]
 words = df.生活习性.astype("str").apply(jieba.lcut).explode()
 words = words[words.apply(len) > 1]
 words = [word for word in words if word not in stopwords]
 stylecloud.gen_stylecloud(" ".join(words),
                           collocations=False,
                           font_path=r'C:\Windows\Fonts\msyhbd.ttc',
                           icon_name='fas fa-square',
                           output_name='tmp.png')
 Image(filename='tmp.png')

image-20211121000607995

генерация кошачьего графа

После приведенного выше анализа у нас есть базовое представление о кошках, а затем мы создадим изображение каждой породы кошек.

Какую картинку мне сделать? Я тщательно все обдумал и составил ментальную карту.

Сначала сгенерируйте категорический текст:

 for a, bs in df.中文学名.groupby(df.体型):
     print(a)
     for b in bs.values:
         print(f"\t{b}")
 中型
     加菲猫
     金渐层
     英短蓝猫
     英短蓝白
     英国短毛猫
     美国短毛猫
     苏格兰折耳猫
     银渐层
     异国短毛猫
     孟买猫
     暹罗猫
     孟加拉豹猫
 大型
     布偶猫
 小型
     缅因猫
     金吉拉猫
     无毛猫
     高地折耳猫
     曼基康矮脚猫
     波斯猫
     橘猫
     阿比西尼亚猫
     德文卷毛猫

На данный момент я вставляю его в карту разума, а затем отредактируйте его часто на некоторое время, чтобы получить:

image-20211121005132096.png