生命不止,折腾不停,最近开始接触了wordpress,发现wordpress真的做得很不错,有很多地方值得学习,很多地方也设置得非常巧妙。在刚安装完了wp后就会有一篇“世界你好”的文章,有点空荡荡,所以我在想可不可用python为wordpress采集一些内容再自动发布上去呢,那么话不多说,让我们开干吧

一、所需库与模块

requests 是一个模拟http请求的库,我们用它来爬取网页。

lxml 是一个解析HTML与XML的库,我们用它来解析网页内容

pymysql 是一个操作MySql的库,我们用它来上传内容到wordpress的数据库

time 是python内置的一个处理时间的模块,我们用它来设置爬取网页的间隔时间

random 是一个python内置的生成随机数的模块,我们用它来生成随机的间隔时间

xpinyin 是一个将汉字转换成拼音的库

二、使用pymysql提交内容到wordpress数据库

一般我们在使用wordpress时都是在后台上面写完然后点击发布,这个过程是这样子的:

浏览器=>form提交=>php=>数据库

而这里我们要跳过前面三个步骤,直接对接数据库:

命令行=>数据库

在通过查看wordpress数据库的wp_posts表的字段后,我写了一段sql语句,并预留了三个位置,为content,title,name,分别代表文章内容,标题,在url显示的名字。

sqlbase="INSERT INTO wp_posts(post_author,post_date,post_date_gmt,post_content,post_title,post_status,comment_status,ping_status,post_name,post_modified,post_modified_gmt,post_parent,menu_order,post_type) VALUE(1,now(),DATE_ADD(now(),INTERVAL '-8' HOUR),'%s','%s','publish','open','open','%s',now(),DATE_ADD(now(),INTERVAL '-8' HOUR),0,0,'post')"

我们要生成一段插入文章的sql语句时就可以这样写

sql=sqlbase % (content,title,name)

接下来要将sql语句提交到wordpress的数据库,这里就需要用到一个python的第三方库pymysql

import pymysql

sqlbase="INSERT INTO wp_posts(post_author,post_date,post_date_gmt,post_content,post_title,post_status,comment_status,ping_status,post_name,post_modified,post_modified_gmt,post_parent,menu_order,post_type) VALUE(1,now(),DATE_ADD(now(),INTERVAL '-8' HOUR),'%s','%s','publish','open','open','%s',now(),DATE_ADD(now(),INTERVAL '-8' HOUR),0,0,'post')"

def upload(title,content,name):
    sql=sqlbase % (content,title,name)
    db=pymysql.connect('数据库ip','数据库用户名','数据库密码','数据库名')
    cursor=db.cursor()
    try:
        cursor.execute(sql)
        db.commit()
    except Exception as e:
        db.rollback()
        print(e)
    db.close()

将提交到wordpress数据库这个操作整合到一个函数中,这样我们在后面使用就会方便一些,将函数中的连接信息修改成wordpress数据库的信息,然后我们来测试一下

>>>upload('我是标题','<p>我是Felix</p>','wo-shi-biao-ti')

因为观察wp_posts表时有些字段内容为空,所以在sql语句中我就没有写,在第一次运行upload()时会有一些提示信息说某些字段为空,忽略即可,然后我们打开wordpress查看

三、爬取内容并上传

在这里,为了方便演示我就选择一个静态的小说网站,在爬取小说网站时,我们主要爬取两种类型的网页,分别为目录页与章节页(文章页)

首先观察章节页,找到章节标题与内容的对应class或者id,通过lxml找到对应的内容,然后根据自己的需求删除或裁剪一些不需要的内容,还有需要注意一下网站的编码问题,这个小说网站直接打印出爬取的内容是乱码所以需要进行一下转码,这里我写了一个的抓取章节页内容的函数

from lxml import etree
import requests

def page(url,booktitle=''):
    response=requests.get(url)
    response.encoding='gbk'
    html=etree.HTML(response.text)
    chapter_title=html.xpath('//h1/text()')[0].split('正文')[1]
    title=booktitle+chapter_title
    content_list=html.xpath('//div[@id="book_text"]/text()')[4:][:-1]
    content=''
    for i in content_list:
        content=content+'<p>'+i+'</p>'

    return [title,content]

测试一下


接下来我们来分析一下目录页,抓取书名与所有章节的链接,可以看到目录页的章节链接是相对地址,所以我们要加上网站的域名将其变为绝对地址,然后我们用time模块与random模块来生成一段时间范围内的随机爬取间隔时间,并且通过第三方库xpinyin来生成wordpress的url所需要的name,下面写了一个menu函数来完成以上操作,输入的参数为目录url与最小爬取间隔时间

import time
import random
from xpinyin import Pinyin
p=Pinyin()

def menu(url,min_time):
    response=requests.get(url)
    response.encoding='gbk'
    html=etree.HTML(response.text)
    booktitle=html.xpath('//h1/text()')[0] #书名
    page_links=html.xpath('//div[@class="article_texttitleb"]//a/@href') #所有章节链接
    i=0
    for link in page_links:
        i=i+1
        try:
            article=page('https://www.tusuu.com'+link,booktitle)
            name=p.get_pinyin(article[0])
            upload(article[0],article[1],name)
            print('page%s finished!' % i)
            time.sleep(random.randint(min_time,min_time+60))
        except Exception as e:
            print('page%s failed!' % i)
            print(e)

    print('All done!')

让我们来测试一下,为了不对别人的网站造成困扰还有不对别人的服务器造成压力,所以这里的最小间隔时间我设置为5分钟即300秒,程序就会在5到6分钟之间进行一次爬取。

>>>menu('https://www.tusuu.com/book/txt21094.html',300)

然后我们隔一段时间再来看一下,因为仅用于测试,所以在第九章时便Ctrl+C退出

四、为文章添加分类(可选)

wordpress并没有强制要求文章要设置分类,如果你需要为文章添加分类,可以看一下下面的方法。

wordpress数据库跟分类有关的有三个表wp_terms,wp_term_relationships,wp_term_taxonomy

wp_term是记录所有分类

wp_term_relationships是记录文章与分类关系

wp_term_taxonomy是记录分类的父分类,分类描述与分类下的文章总数

我们首先在wp_term里找到分类的id,然后在插入文章后与commit之前通过cursor.lastrowid获取最新文章的id,这时候添加分类,接着为wp_term_taxonomy表中分类的文章统计数加一,最后再commit,这里改写了一下upload函数

category_sqlbase="INSERT INTO wp_term_relationships(object_id,term_taxonomy_id,term_order) VALUE(%s,%s,0)"
count_sqlbase="UPDATE wp_term_taxonomy SET count=count+1 WHERE term_id ='%s' "

def upload(title,content,name,cate_id):
    sql=sqlbase % (content,title,name)
    db=pymysql.connect('数据库ip','数据库用户名','数据库密码','数据库名')
    cursor=db.cursor()
    try:
        cursor.execute(sql)
        sql2=category_sqlbase % (cursor.lastrowid,cate_id)
        sql3=count_sqlbase % cate_id
        cursor.execute(sql2)
        cursor.execute(sql3)
        db.commit()
    except Exception as e:
        db.rollback()
        print(e)
    db.close()

upload函数多添加了一个参数cate_id为分类的id,我们来测试一下,我为wordpress添加了一个新闻分类,通过查看wp_terms表得知新闻分类id为4

>>>upload('我是新闻标题','我是新闻内容','wo-shi-xin-wen-biao-ti',4)

现在就可以看到文章被添加到了新闻的分类了,当然你也可以动态地添加新的分类,然后通过sql语句用名字找到对应的id。

五、其他

不同的网站一般结构都是不同的,所以上面爬取部分的代码在别的网站上一般也是用不了的,甚至因为网站更新在同一个网站也可能用不了,所以爬取部分大家可以根据自己的需要修改一下。

对于动态页面我们可以调用页面上的一些js,获取返回的结果。

如果你担心被网站禁ip,可以挂代理,或者将采集程序放到挂机宝上,也可以选择模拟百度UA,这个可以在requests上设置。

以上所使用网站仅用于学习探讨,请勿对他人网站进行频繁访问攻击,并注意版权问题,造成法律纠纷与财产损失与本站无关,请自行负责!

评论

Felix 管理员

今天更新了一下文章,添加了设置文章分类的方法!

回复

Felix 管理员

wordpress是挺不错的,生态很好

回复

  • 最新随笔

  • 尝试让DALLE生成一些连续的精灵图,让gpt帮忙生成一些提示词,如果能稳定输出的话就很强大了。
    让gpt帮忙生成的DALLE提示词
    "Generate a pixel art sprite sheet of a character walking in four directions (north, south, east, west) in a retro video game style."
    "Create a series of pixel art frames showing a character performing different actions like walking, running, jumping, and attacking in a classic 2D game aesthetic."
  • 路过别人山庄的门口,被一条大黑狗边叫边追过来,幸好骑电动车,不然还不一定跑得过,哈哈哈哈哈哈哈哈哈哈。
  • 最近两周也没咋出去玩,主要也是觉得没啥好玩的(笑哭)。看完布莱恩阿瑟的《复杂经济学》后,里面那个酒吧问题勾起我的兴趣,最近空了就花了些时间实现个python版本,顺便搞了篇博文,很享受这种新知识能和已有知识碰撞的感觉。(配张前段时间拍的图片,梧桐山门口前面那条路,挺漂亮的)
  • 盐田港夜景
  • 为啥这猫总喜欢喝杯子里的水
  • 确实开始冷了,在树林里至少要比人类聚集区低个几度,进出入口就能很明显感觉到。看看深圳水库的风景,貌似后面的视野更开阔。
  • 给随笔加了多图的功能,传一传周末拍的风景图,漫无目的的逛也挺好玩的。
  • 逻辑自洽是一套体系的根基,最根本的因素,最吸引人的地方