import requests
from bs4 import BeautifulSoup
instructors_page ='https://www.datacamp.com/instructors?all=true'
instructor_link_selector ='.instructor-block__description .instructor-block__link'# CSS class of the link
instructor_name_selector ='.mb-sm'# CSS class of the name
instructor_resp = requests.get(instructors_page)
soup = BeautifulSoup(instructor_resp.text,'lxml')
instructor_urls =[url['href']for url in soup.select(instructor_link_selector)]
instructor_names =[name.text.strip()for name in soup.select(instructor_name_selector)]
instructor_urls =['https://www.datacamp.com'+ url for url in instructor_urls]技术支持
词组匹配(带引号)会在用户搜索该精确字串,且其前后带有任何词时触发您的广告。因此“best data science course”或“data science course online”都会触发我们的广告。
广泛匹配(无标点)会在用户搜索与“data science course”相似或相关的任何内容时触发我们的广告。这取决于 Google 的算法,需谨慎使用,因为它可能在有人搜索“data science platform”时触发广告,而这并非我们要推广的内容。我更喜欢使用“改良广泛匹配”,因为它会进一步收紧定向。它的含义基本上是当有人搜索该词的任意派生形式,而非意义相近的其他词时才会触发。其记号是在词前加“+”。因此,“+game”会被“gaming”“gamers”触发,但不会被“play”触发。
col_names =['Campaign','Ad Group','Keyword','Criterion Type']
instructor_keywords =[]
words =['course','courses','learn','data science','data camp','datacamp']
match_types =['Exact','Phrase','Broad']for instructor in instructor_df['name']:for word in words:formatchin match_types:ifmatch=='Broad':
keyword ='+'+' +'.join([instructor.replace(' ',' +').lower(), word])# modified broach matchelse:
keyword = instructor.lower()+' '+ word
row =['SEM_Instructors',# campaign name
instructor,# ad group name
keyword,# instructor <keyword>match]# keyword match type
instructor_keywords.append(row)# do the same by having the keywords come before the instructor namefor instructor in instructor_df['name']:for word in words:formatchin match_types:ifmatch=='Broad':
keyword ='+'+' +'.join([word, instructor.replace(' ',' +').lower()])else:
keyword = word +' '+ instructor.lower()
row =['SEM_Instructors',# campaign name
instructor,# ad group name
keyword,# <keyword> instructor match]# keyword match type
instructor_keywords.append(row)
instructor_keywords_df = pd.DataFrame.from_records(instructor_keywords,
columns=col_names)print('total keywords:', instructor_keywords_df.shape[0])
instructor_keywords_df.head()技术支持
defgenerate_keywords(topics, keywords, match_types=['Exact','Phrase','Broad'],
campaign='SEM_Campaign'):
col_names =['Campaign','Ad Group','Keyword','Criterion Type']
campaign_keywords =[]for topic in topics:for word in keywords:formatchin match_types:ifmatch=='Broad':
keyword ='+'+' +'.join([topic.lower().replace(' ',' +'), word.replace(' ',' +')])else:
keyword = topic.lower()+' '+ word
row =[campaign,# campaign name
topic,# ad group name
keyword,# instructor <keyword>match]# keyword match type
campaign_keywords.append(row)# I said more than twice! :) for topic in topics:for word in keywords:formatchin match_types:ifmatch=='Broad':
keyword ='+'+' +'.join([word.replace(' ',' +'), topic.lower().replace(' ',' +')])else:
keyword = word +' '+ topic.lower()
row =[campaign,# campaign name
topic,# ad group name
keyword,# <keyword> instructormatch]# keyword match type
campaign_keywords.append(row)return pd.DataFrame.from_records(campaign_keywords, columns=col_names)技术支持
topics =['R','Python','SQL','Git','Shell']# listed on the /courses page
keywords =['data science','programming','analytics','data analysis','machine learning','deep learning','financial analysis','data viz','visualization','data visualization','learn','course','courses','education','data import','data cleaning','data manipulation','probability','stats','statistics','course','courses','learn','education','tutorial']# @marketing_team: this list can / should be refined or # expanded based on the strategy and how specific the # targeting needs to be
tech_keywords = generate_keywords(topics, keywords, campaign='SEM_Technologies')print('total keywords:', tech_keywords.shape[0])
tech_keywords.head()技术支持
这可能是最具体、因此也是最相关的人群定位分段。如果有人搜索“data visualization with r”,而 DataCamp 正好有这门课程,那么广告会极其相关,因为您会有一个精准满足该用户需求的落地页。
不过有个小问题。有些课程名称并不符合用户通常的搜索方式:“Machine Learning with the Experts: School Budgets”“Sentiment Analysis in R: The Tidy Way”。这些并不是糟糕的课程名,但在选择人们可能用于搜索它们的合适关键词时,需要多加留意。
再次像讲师广告系列那样,您可以抓取课程名称及其对应的 URL:
courses_page ='https://www.datacamp.com/courses/all'
course_link_selector ='.courses__explore-list .course-block'
course_resp = requests.get(courses_page)
soup = BeautifulSoup(course_resp.text,'lxml')
course_urls =[link.contents[1]['href']for link in soup.select(course_link_selector)]
course_urls =['https://www.datacamp.com'+ url for url in course_urls]
course_names =[link.h4.text for link in soup.select(course_link_selector)]技术支持
skills_page ='https://www.datacamp.com/tracks/skill'
skills_link_selector ='#all .shim'
skills_resp = requests.get(skills_page)
skill_soup = BeautifulSoup(skills_resp.text,'lxml')
skills_urls =[link['href']for link in skill_soup.select(skills_link_selector)]
skills_names =[skill.replace('/tracks/','').replace('-',' ')for skill in skills_urls]
skills_urls =['https://www.datacamp.com'+ url for url in skills_urls]技术支持
职业
career_page ='https://www.datacamp.com/tracks/career'
career_link_selector ='#all .shim'
career_resp = requests.get(career_page)
career_soup = BeautifulSoup(career_resp.text,'lxml')
career_urls =[link['href']for link in career_soup.select(career_link_selector)]
career_names =[career.replace('/tracks/','').replace('-',' ')for career in career_urls]
career_urls =['https://www.datacamp.com'+ url for url in career_urls]技术支持
tracks_df = pd.DataFrame({'name': skills_names + career_names,'url': skills_urls + career_urls
})
tracks_df['name']=[x.title()for x in tracks_df['name']]
tracks_df.head()技术支持
%matplotlib inline
import matplotlib.pyplot as plt
adgroup_lengths = pd.Series([len(adgrp)for adgrp in full_keywords_df['Ad Group'].unique()])
long_adgroups =sum(adgroup_lengths >30)
plt.figure(figsize=(9,6))
plt.hist(adgroup_lengths, rwidth=0.9, bins=50)
plt.vlines(x=30, ymin=0, ymax=10, colors='red')
plt.title(str(long_adgroups)+' ad group name lenghts > 30 (don\'t fit in a headline)', fontsize=17)
plt.xlabel('Ad Group Name Lengths', fontsize=15)
plt.ylabel('Count', fontsize=15)
plt.yticks(range(11))
plt.xticks(range(0,51,5))
plt.grid(alpha=0.5)
plt.show()技术支持
Description =['Learn Directly From the Top Experts in the Field. 20% off Annual Subcriptions','Be Ahead of the Curve, Master Data Science Skills. $29 / Month. Cancel Anytime','Choose From a Wide Variety of Topics Tuaght by the Best in the World. Start Now']
Description =[x for i inrange(n_adgroups)for x in Description ]
full_ads_df['Description']= Description
full_ads_df.head()技术支持
benefits =[x for i inrange(n_adgroups)for x in benefits]
headlines =[split_string(x)for x in full_ads_df['Ad Group']]
full_ads_df['Headline 1']=[x[0]for x in headlines]
full_ads_df['Headline 2']=[x[1]if x[1]else benefits[i]for i, x inenumerate(headlines)]print('total ads:', full_ads_df.shape[0])
full_ads_df.head(9)技术支持
作为 DataCamp 的重度用户已有两年时间,我学到了不少东西。我的主营业务是在线营销,而我从所学的数据科学技能中获益良多。现在我能够管理规模更大、结构更复杂的广告系列,并高效维护它们。由于我已经相当熟悉网站上的内容、各个主题以及 R 和 Python 的不同软件包,我就想以练习为目的,试着为 DataCamp 创建搜索广告系列。
在本教程中,您将涉及以下主题:
搜索引擎营销(SEM)与广告系列
什么是 SEM?
在竞争日益激烈的市场中,SEM 是发展业务最有效的方式之一。它是通过在搜索引擎上购买广告来获取网站流量的过程。Google AdWords 是最流行的线上广告形式之一:您为与业务相关的关键词在搜索引擎的赞助链接中争取广告位,然后为每次点击向搜索引擎支付费用。
按点击付费的成本可能相当可观,因此合理规划并分组关键词和广告非常重要,这样您才能控制成本,并有望获得盈利的广告系列。
尽管决定每次点击价格的具体过程被严密保密且受多种因素影响,但核心思想是:您的广告越相关,点击成本就越低。
如何设置搜索广告系列
在设置广告系列之前,您通常会先制定预算、挑选关键词并查看竞争情况。同时,您要确保落地页没有问题。然后,您可以设置广告系列:撰写第一条广告、完善其细节,并设置转化跟踪。本教程主要涵盖基于不同落地页来生成大量关键词和广告的流程。
不过,在开始之前,让我们先看看搜索广告系列到底是什么!
广告组
要启动搜索广告系列,您首先需要为广告组制定计划。广告组是组织的基本单元,在这里您将关键词、广告和落地页进行映射。但这三者究竟是什么?
正确映射这三个要素大约占工作量的 70-80%。如果这一步做得好,后续维护和调整就会容易得多。
这意味着,为了对用户更具体、更相关,您需要推广自己拥有的产品,核心是通过合适的信息或预期,将合适的人送到合适的页面。一个好的广告系列结构会反映并遵循网站的结构,而网站结构本质上反映了业务战略。
注意 每个广告组都必须属于某个广告系列。在广告系列层级,您可以设置适用于该系列内所有广告组的参数,如语言定向、地域、设备、投放时间等。
搜索广告系列,分步进行
上一节中,您从宏观层面了解了搜索广告系列:看到关键词、广告和落地页属于同一个广告组,并需要为这个组织基本单元制定计划,以使这三者的映射能够反映您的业务战略。本节将更深入地探讨搭建广告系列可以做些什么,重点关注您在本教程中将经历的步骤。
如上所示,这是您希望实现的映射。最终,您希望得到两个主要的 DataFrame:一个用于关键词,另一个用于广告。如下所示是它们可能的样子。
完成这些之后,您就可以将它们以逗号分隔值(CSV)文件的形式上传到 Google AdWords,或其他工作方式完全相同的平台。除了 Bing Ads、Yandex、百度等平台之外,Google AdWords 仍是搜索营销人员使用最广泛的付费搜索平台。
注意 如果您要将数据导入 Google Adwords 或 Bing Ads 之外的平台,则需要做一些小调整!
业务案例:DataCamp
如引言所述,您希望为 DataCamp 创建搜索广告系列。观察人们表达对该公司产品(即数据科学教育)兴趣的不同方式,您很容易就能列出一份初步清单:
在本教程中,您不会经历传统的关键词研究阶段,因为您可以借助编程语言的力量生成所有可能的组合,并将它们分组到相应的广告系列和广告组中。
因此,要完成此设置,您需要了解两件主要的事情:
为您的 SEM 广告系列生成关键词
让我们从生成关键词开始!
1. 生成讲师关键词
此广告系列将定位搜索 DataCamp 任一讲师课程的人群。
您可以将关键词限定在“
course by <instructor name>”,也可以选择更广泛的关键词集,仅定位讲师姓名。起步阶段,最好将目标锁定在带有“course”或“courses”的姓名上,观察效果如何。您还需要检查所拥有的姓名中,是否有与其他名人同名或非常常见的姓名,然后需要对该讲师的关键词进行收紧。
先获取讲师姓名及其各自的 URL:
将它们保存到一个 DataFrame,供稍后使用。URL 之后将用于生成广告。
现在您已经有了讲师姓名,将使用一个模板,将每个姓名与一组与主题相关的关键词组合,主题主要是该讲师的课程。
下面代码中使用的变量:
col_names:这是最终将上传至 Google AdWords 的表格标题列表。words:将与讲师姓名组合以生成完整关键词/短语的词。match_types:更多详情请参阅AdWords 帮助中心,这里先介绍基础概念。[data science course]、"data science course" 和 data science course 在技术上是三种不同的关键词。
基本上,您在遍历讲师姓名、不同关键词以及所有匹配类型,以获得所有可能的组合。我们做了两遍,一次是“讲师姓名 + 关键词”的模板,另一次是“关键词 + 讲师姓名”。
现在,您只需对所有分段重复上述过程,仅在关键词和数据提取方式上做少量修改。
我从R for Data Science学到一个很好的准则:如果您需要复制粘贴超过两次,那就该写个函数了!
来试一下:
看起来不错。现在让我们为每个分段生成相应的主题和关键词!
2. 技术类关键词
3. 生成课程关键词
这可能是最具体、因此也是最相关的人群定位分段。如果有人搜索“data visualization with r”,而 DataCamp 正好有这门课程,那么广告会极其相关,因为您会有一个精准满足该用户需求的落地页。
不过有个小问题。有些课程名称并不符合用户通常的搜索方式:“Machine Learning with the Experts: School Budgets”“Sentiment Analysis in R: The Tidy Way”。这些并不是糟糕的课程名,但在选择人们可能用于搜索它们的合适关键词时,需要多加留意。
再次像讲师广告系列那样,您可以抓取课程名称及其对应的 URL:
课程也将使用相同的方法(调用
generate_keywords()函数),但需要谨慎,如上所述,部分课程名并不是人们会去搜索的表达,需要逐一审查。以下设置足以起步,之后您可以查看数据并做出决策。请注意,下面使用空字符并非错误。课程名称本身足够冗长且具体,适合作为关键词本身,而无需添加“learn”“course”等限定词。因此,您将同时使用仅包含课程名的关键词,以及加入限定词的组合。
4. 主题类关键词
这些基本上是大众感兴趣的通用主题。它们对应“学习路径(tracks)”版块,包含技能和职业两个子版块。就您的目的而言,可以将它们归为同一广告系列。流程仍与前面各节相同!
技能
职业
最后,将
instructor_keywords、tech_keywords、course_keywords和tracks_keywords中的所有关键词连接起来,汇总到一个大的 DataFrame 中:现在您已经可以使用这些关键词了!如果想查看完整数据集,请点击这里。接下来,您需要为每个广告组生成广告。
让我们来生成广告。
广告生成与文案撰写
您目前已有如下内容:
full_keywords_dfDataFrame 中,广告系列与广告组名称已正确映射有了这些,您可以按照以下计划进行:
'name'、'url')DataFrame 中创建并添加Campaign列'name'、'url')DataFrame 合并为一个大的 DataFrame为所有广告组生成全部广告;每条广告包含以下字段(这些将是您正在处理的同一 DataFrame 中的新列):
确保与
keywordsDataFrame 保持一致生成广告的过程,就是把主题名称(课程、技术、讲师等)替换到模板中相应位置,并为您拥有的每个广告组制作 2-3 个广告变体。
广告模板
需要注意的是,虽然将广告组名称填入相应位置的过程很直接,但问题在于您需要让各字段的长度不超过上述限制。由于课程和主题名称差异很大,您需要想办法应对。
让我们看看问题有多大:
看来这个问题并不轻松,也没有简单直接的解决办法。理想情况下,我们希望在两个标题中包含我们所推广产品(课程)的完整标题。
我想过不同的应对方式,决定写一个简单的算法,将名称拆分为两个短语,每个不超过三十个字符。
该算法并不适合通用场景,需要稍作调整才能通用,但对于本数据集已经足够好用:
我平时不常这样做,但我喜欢这种技巧,觉得在创建其他广告系列时也会用到。这是编写教程的一个意外收获!
现在我们来思考要写的模板。
我常用的通用广告模板包含以下要素(通常按此顺序):
要把这些全部塞进一条类似推文长度的广告并不容易,而且部分内容可能会重叠。但我们会尽力而为。
创建
Campaign列合并所有(
'name'、'url')DataFrame生成广告
简单回顾一下当前进度。您现在有了包含
Campaign、Ad Group和Final URL列并正确映射的广告 DataFrame。接下来需要添加Headline 1、Headline 2和Description字段。请记住,您将为每个广告组添加三种不同的广告变体。这主要是为了测试目的,以观察用户点击情况、哪些广告的转化更高等。最终,DataFrame 的行数应为当前的三倍。
我们先在
full_ads_df中将每一行复制三遍:现在添加上面创建的三种不同的 Description。
接着,向 DataFrame 添加
Headline 1和Headline 2。您就快完成了!当广告组名称长度不超过 30 时,收益语将作为
Headline 2填入。在这种情况下,您会有空白字段,我们将用上述收益语之一填充。如您所见,“Intro to Python for Data Science” 足够长,需要拆成两个字段,因此我们按原样保留以确保清晰。而“Introduction to R” 能放入第一个标题,于是我们在
Headline 2中插入了三种不同的收益语。大功告成!
仔细检查细节
做个快速检查,确保两个 DataFrame 中的广告系列与广告组名称一致。
上传并启动
如前所述,本教程只涵盖了 SEM 广告系列中的特定步骤,因此需要您对搜索引擎营销的运作有基本了解。如果您想进一步了解上传和启动广告组的机制和细节,可以查看 AdWords 入门指南。若想系统学习不同领域的完整课程,可以访问 Google Academy for Ads。
数据科学与 SEM:还有更多可探索!
现在有了这两个 CSV 文件,您即可上传并开始投放广告系列。您还需要设置每日预算、地域定向以及其他一些参数,但大体而言,已经可以出发了。
如需查看 CSV 文件,请见:
希望本教程对您有所帮助。感谢阅读!如果您愿意分享借助 Python 完成的增长项目,欢迎在 Twitter 上联系我 @eliasdabbas。