狂码近万字,只为让你学会优化编程,用python实现完美标题自动生成

SEO Python公开课

  因为近期官网上线了很多新功能,最近一段时间我介绍5118自家产品确实有点多,有些朋友建议,除了介绍自家的产品,也希望我多提供一些干货,供大家学习。

  做为实战派,崇尚极客精神,于是有了这篇文章,边撸代码边讲课。

  如果你觉得有用,请一定点赞,让我更有动力来制作一系列SEO编程高级公开课。



  过去十五年来做过很多流量站,也为数万网站提供SEO服务,仔细回想,所有SEO工作里面,最重要但又效率低的工作,就是为页面编写TDK,特别是页面标题Title,是所有SEO工作里面最最重要的工作,如果这件工作没有做好,其他工作做的再好也是白搭,如果Title写好了,其他工作稍有不足也可以被弥补。


  所以今天就把一直在使用的方法详细的为大家讲解,并附带上代码,我们拿“月亮虾饼怎么做”的SEO为例,主要思路如下:




TOP20的页面教我写Title

在百度搜索“月亮虾饼怎么做”。

记录所有页面的真实标题(不是百度缩减过的标题)。

将所有标题中的词汇全部记录,并计算词汇出现频次。

将高频词汇用人类语言串联起来成为句子,即对人类友好,又能够击中最多高频关键词。




  以上步骤核心思想是:如果搜索词汇,某个网页在百度搜索结果排名表现好,那么他的标题一定是写的出色,而如果把所有这些页面标题精华全部汇总计算,得出最精华的句子,那么这个句子作为标题就是最完美的。


  也就是说既然排名靠前的这些网页在百度表现好,就应该尽量的学习和参考他们的做法,将这些精华全部吸收,毕竟众人的智慧一定要比一个人的智慧要强很多,基于数据的结论一定比感性的猜测更有说服力。


  但是每个关键词都要手动完成上表中四个步骤,显然是不现实的,我们要通过程序来尽量自动化,减少人的工作量,下面我将使用python来实现用爬虫分析标题工作的雏形代码,满足我们对标题自动生成的需求。


  首先请先安装好python和pycharm,不懂的朋友可以参考这篇文章来安装python程序的运行环境和pycharm编辑器,安装完毕后,下面就开始我们的SEO完美标题python爬虫之旅。




1
爬虫,你好!





import requests


url = 'http://www.baidu.com/s?wd=月亮虾饼怎么做&rn=50'

response = requests.get(url)


print(response)



第一句,import requests,是导入requests包,这个包是一个简洁的python的http库,我们在编写爬虫程序时,经常会用到它,具体可以参考这篇文章


第二句,我们将需要访问的网址,赋值给一个变量url,方便后面使用,关于python变量的使用,具体可参考这篇文章


第三句,我们用requests.get方法,获取url的返回,这里response并不是返回的html,而是一个响应对象,里面包含除了html外的其他很多http的响应信息,具体可以参考这篇文章


第四局,打印response对象,如果我们运行,会看到下图所示返回结果,返回200代码标识访问成功。

另外比较熟悉的返回代码404,表示页面不存在,具体的http返回代码可以参考这篇文章


我们将上面代码保存到1_1.py文件中(py是python程序的常用文件后缀),在编辑器中运行ing1_1.py ,结果如下:


image.png


我们看到红箭头所指,返回200状态码,表示访问正常


image.png


如上图,我们将代码稍加改造,把

print(response)

改为

print(response.content)


重新在编辑器中运行1_1.py,运行后返回结果就是html了,如图:


image.png


完整代码:
https://shimo.im/docs/r05eM6l20iQSYDpw/



2
兼容各编码



通过上文代码,获取百度搜索结果页面html后,发现里面的中文全部是乱码


image.png


写过Html的朋友都知道,网页文件有各种编码,例如中文常用的gb2312字符集,例如针对Unicode的可变长度字符编码utf8,这两个是我们最常用的字符编码,如果希望了解字符集概念,请参考这篇文档


当我们不清楚网页是什么编码时,往往通过Html中的meta charset来确认。


image.png


那该如何通过程序自动确定网页的真正编码呢?


我们可以使用 chardet 这个第三方库,这个库能够快速的检测当前网页文件使用的是什么编码,它的原理是通过文件的顺序字节来尝试确定当前文字的编码,感兴趣了解详情的朋友可以查看官网文档



import chardet



通过上方代码引入 chardet 第三方库,然后我们对第一节中的代码稍作扩展:



import chardet


url = 'http://www.baidu.com/s?wd=月亮虾饼怎么做&rn=50'

response = requests.get(url)

htmlEncoded = response.content


detectResult = chardet.detect(htmlEncoded)

encoding = detectResult['encoding']

print('页面编码:', encoding)

html = str(htmlEncoded, encoding)

print('页面Html:', html)


5118.com



我们在代码中加入了红框所框选的代码

image.png

保存文件到1_2.py,在编辑器中运行后,返回结果如下:

image.png


上图红线圈选的,正是我们用print语句打印的两个结果

一行是chardet探测出的页面编码

另一行是用这个编码读取的网页内容


现在页面上内容全部显示为中文了,如图:

image.png


完整代码:
https://shimo.im/docs/r05eM6l20iQSYDpw/



3
获取搜索结果着陆页信息




image.png


通过第1、2步,获取百度搜索结果页html后,我们希望通过html获取页面中的排名结果着陆页的准确标题,因为Title过长时,百度将会截取掉Title后过长的部分,变成省略号,为了获取准确的标题,需要获得着陆页的真实url,从而读取这个url来获取页面的Title,下面我们再对代码进行改造:



import requests
import chardet

from bs4 import BeautifulSoup


url = 'http://www.baidu.com/s?wd=月亮虾饼怎么做&rn=50'

response = requests.get(url)

htmlEncoded = response.content

detectResult = chardet.detect(htmlEncoded)

encoding = detectResult['encoding']

html = str(htmlEncoded, encoding)


soup = BeautifulSoup(html, 'html.parser')

items = soup.select('h3 a')

for item in items:
    resultRedirectUrl = item.attrs['href']
    print(resultRedirectUrl)


5118.com



为了能够更快的分析页面html上的dom结构,我们引入BeautifulSoup 这个第三方库,你可以通过

pip install beautifulsoup4

安装这个第三方库,因为这些库不是官方自带的,所以需要使用pip install命令来安装到本地,如果你使用的pycharm编辑器,可以通过这篇文章来安装第三方库。


下面我们来详细讲解新增代码的具体用途



soup = BeautifulSoup(html, 'html.parser')



这行代码是表示通过BeautifulSoup来解析html变量中Html代码,使用html.parser解析器,因为BeautifulSoup还有其他几种解析器,如xml、html5lib等,所以这里必须确定使用什么解析器,具体参考官方文档


image.png


items = soup.select('h3 a')



这句话是通过css选择器来从html的dom树中获取到对应的节点,例如我们这里是要获取html中所有h3标签下的a标签dom节点元素,所以我们使用了 'h3 a' 这个选择器,如果我们在chrome浏览器中点击F12来查看每个着陆页对应的元素,我们就知道为什么要使用这个选择器。


image.png


我们也可以在chrome浏览器的F12中的控制台中运行js代码document.querySelectorAll('h3 a') 来查看使用的选择器是否正确


image.png

例如上图在百度显示前10个结果的搜索页上使用选择器'h3 a',就会显示发现了10个a标签节点。



for item in items:
    resultRedirectUrl = item.attrs['href']
    print(resultRedirectUrl)
5118.com



上方的这三行代码是我们循环提取所有符合选择器的a标签节点,打印出a标签的href属性值,也就是a标签对应的锚链接,如下图。


image.png


这个链接是百度已经加密过的链接,在后面的代码中我们将会用到。


我们将整个代码保存到1_3.py中,在pycharm编辑器中运行这段代码,结果如下:


image.png

上面打印了一堆url,也就是下图的网址,是百度搜索页上所有百度加密过的着陆页,就这么简单。


image.png


完整代码:
https://shimo.im/docs/r05eM6l20iQSYDpw/



4
解密百度着陆页url



通过上面3个步骤,获取了着陆页的具体url,现在需要解密着陆页的url,下面我们来改造第3节的代码达到这个目的。



import requests
import chardet

from bs4 import BeautifulSoup


url = 'http://www.baidu.com/s?wd=月亮虾饼怎么做&rn=50'

response = requests.get(url)


htmlEncoded = response.content

detectResult = chardet.detect(htmlEncoded)

encoding = detectResult['encoding']

html = str(htmlEncoded, encoding)


soup = BeautifulSoup(html, 'html.parser')

items = soup.select('h3 a')


for item in items:

resultRedirectUrl = item.attrs['href']


if 'http://' in resultRedirectUrl or 'https://' in resultRedirectUrl:


itemHeadRes=requests.head(resultRedirectUrl, verify=False)


itemUrl = itemHeadRes.headers['Location']


print('搜索结果真实网址:', itemUrl)


5118.com



通过增加红色这段代码,我们把百度搜索结果中的所有机密过的网址,通过Http Head命令解密成了真实的url,具体每段代码的作用如下:



if 'http://' in resultRedirectUrl or \
    'https://' in resultRedirectUrl:

这段代码是确保url是一个正常的url,因为我们在上节中发现从百度的搜索结果html中使用'h3 a'这个选择器提取a标签节点,可能会提取到百度视频推荐的一个结果


image.png

也就是下图这个链接

image.png


这个url是个百度视频搜索的相对链接,所以我们这里加上了判断,必须在url中包涵'http://' 或者 'https://'



itemHeadRes=requests.head(resultRedirectUrl,verify=False)

itemUrl = itemHeadRes.headers['Location']

print('搜索结果真实网址:', itemUrl)


5118.com



上方代码是使用http协议中的head命令来访问百度加密连接,head命令比get命令返回信息更加精简,只会返回http头信息,这样我们就不用读取一大段html就能得到解密后的url,关于http头信息的内容请参考这篇文章


image.png


通过headers的Location属性,便能得到解密后的url,我们把这个解密后的url网址存储到itemUrl变量中,以便后续读取页面Title使用。 


我们将整段代码保存到1_4.py,在编辑器中运行后,效果如下:


image.png



这样每个着陆页解密后的网址就提取出来了,so easy。


完整代码:
https://shimo.im/docs/r05eM6l20iQSYDpw/



5
获取所有着陆页标题



上一节我们得到了着陆页的所有解密后的网址url,现在要做的就是批量读取这些网址,获得它们的标题,代码改造如图:


image.png


上图红色框部分代码如下:



itemRes = requests.get(itemUrl, verify=False)

if itemRes.status_code == 200:

itemHtmlEncoding=chardet.detect(itemRes.content)['encoding']


itemHtml=str(itemRes.content,itemHtmlEncoding,errors='ignore')


itemSoup=BeautifulSoup(itemHtml,'html.parser')


if itemSoup.title is not None:

itemTitle = itemSoup.title.text.strip()

print('着陆页Title:', itemTitle)


5118.com



我们同样使用request库,调用和第一节一样的http get命令来读取每个着陆页的html代码,这里也使用了chardet来探测网页编码,因为我们不能确定每个着陆页用的具体什么编码,如果忘记了网页编码的内容,请回看本文的第二节。



读取每个着陆页的html后,将html存入itemHtml的变量中,然后通过下面代码提取出html中的title


itemSoup=BeautifulSoup(itemHtml,'html.parser')


if itemSoup.title is not None:

itemTitle = itemSoup.title.text.strip()

print('着陆页Title:', itemTitle)


5118.com



这里看到又再次使用了第三节中提到的 BeautifulSoup 第三方库来解析html,直接通过title属性来获得html中的title,因为有些html可能没有title,所以我们这里使用了一个判断,如果title is not None,表示如果title标题不为空那么就提取title,strip 函数是用来把标题字符串两端的空白去掉,因为我们知道很多时候title标记里可能会有多余的空格。


将上面的代码保存为1_5.py,在编辑器中运行,结果如下:


image.png


这样百度搜索结果所有的着陆页标题就得到了,离成功越来越近。


完整代码:
https://shimo.im/docs/r05eM6l20iQSYDpw/



6
获取所有标题中的词汇



上一节我们得到了所有标题,那么接下来就要分析出所有标题到底都包含哪些词汇。


改造代码如下:


image.png

image.png


导入了一个第三方分词库jieba
import jieba

这个库可以把我们得到的title标题分词成词汇。


我们看到下面这段代码,这里我们引入了5118自己的一个大型用户词典,收录中文中大部分的词汇,如果你有自己的用户词典,也可以加载自己的用户词典,其实jieba这个库自带了系统词典,只不过可能没有5118的齐全,分词的效果很大程度上和词典的质量有很大关系。



rootPath = os.path.dirname(os.path.realpath(__file__))
userDictPath = os.path.join(rootPath, 'jiebadic.csv')
jieba.load_userdict(userDictPath)
jieba.initialize()
5118.com



前面两行代码组装出当前py文件所在目录下jiebadic.csv用户词典文件的完整路径,然后通过jieba的load_userdict方法加载这个文件,最终通过initialize这个函数进行初始化。


接下来我们看到下图中的三段代码:


image.png

这三段代码目的是将所有标题累加在一起,放入allTitleStr变量,便于最后这段代码通过jieba分词库进行分词



titleWords = [word for word in jieba.lcut(allTitleStr, cut_all=False) if len(word) > 1]



这段代码的意思是通过jieba的lcut方法分词成一个列表,并且只保留长度大于1的词汇,jieba第三方库的具体使用方法,请参考这篇文章
 

将代码保存为1_6.py,在编辑器中运行结果如下:


image.png


在最后一行结果中我们已经看到分词后的所有词汇,离成功只差一步。


完整代码:
https://shimo.im/docs/r05eM6l20iQSYDpw/



7
得出标题高频词汇



通过1-6节已经得到了标题中的所有词汇,但是知道哪些词汇是所有着陆页标题中使用最多的词汇才是我们最终目的。


接下来通过Counter这个第三方库,快速对词汇列表进行词频统计,同样通过python的import引入Counter对象



from collections import Counter



通过python对字典进行倒序排列,以找到最高频的那些词汇,我们在第6节的代码底部加入下方代码。



titleWordsDic = dict(Counter(titleWords))

titleWordsSortedList = sorted(titleWordsDic.items(), key=lambda x: x[1], reverse=True)

for item in titleWordsSortedList:

print(item[0], ':', item[1])


5118.com


下面逐行说明上方代码:

titleWordsDic = dict(Counter(titleWords))

这一句是通过Counter第三库对象,计算所有词汇列表中每个词汇的频次,并且转换成一个字典。




titleWordsSortedList = sorted(titleWordsDic.items(), key=lambda x: x[1], reverse=True)


这一句是通过python的排序方法,按照词汇频次倒序,以优先查看频次最高的词汇。



for item in titleWordsSortedList:

print(item[0], ':', item[1])


这一句是循环整个倒序后的词频列表,并且打印出词汇和词汇出现的频次。


把以上四段代码贴到第6节的代码下,保存为1_7.py后,在编辑器中运行,结果如下:


image.png


这里表示所有着陆页标题中,"月亮"出现了80次,"虾饼"出现了32次,"家常做法"出现了14次,下面我们就开始利用这个数据。


完整代码:
https://shimo.im/docs/r05eM6l20iQSYDpw/



8
最终组成页面标题Title



通过以上7个小节形成的代码,获得百度搜索结果Top50所有网页标题高频词后,我们可以用SEO原始方法利用各种分隔符来进行拼接,例如:


月亮虾饼做法_月亮虾饼怎么做_月亮虾饼家常做法

月亮虾饼做法,台湾月亮虾饼图解步骤,月亮虾饼菜谱


不过按照多年SEO经验,最好是通过人类语言将这些词用通顺的话语组织成一句话,这样对用户更加友好,能够在搜索结果中脱颖而出,更容易被点击,也更符合百度的着陆页规范,例如:


月亮虾饼好吃吗?教你家常做法食谱,台湾怎么做


用标题击中最多的流量高频关键词,并且还要让用户读标题后,还能够感兴趣点击,比起分隔符拼接,这才是SEO标题的高级技巧。




9
给他们秀一波操作




完整代码:
https://shimo.im/docs/r05eM6l20iQSYDpw/



运行上面的代码,聪明的你可以想想这段代码稍加修改后,还能用来做什么?


  1. 监控海量百度PC端关键词排名

  2. 采集某个关键词的所有文章(需要正文提取)

  3. 获取百度搜索结果着陆页所有解密的url

  4. 获取所有着陆页的Meta description

  5. 获取所有着陆页的外链

 

本文代码其实已经是一个小型爬虫的雏形,你可以用这段代码作为原形,完成很多你以前可能无法完成的批量化数据工作。在你的上司和同事面前秀一波数据,或许会让他们刮目相看,让你的优秀射瞎他们的双眼。





系统通知