最近想建设一个自己的个人网站,把现在CSDN上面的我的博客内容搬运过去,因此想用Python来做一个web爬虫,自动把我在CSDN上的博客文章下载下来并做一些格式转换,发布到我的个人网站上。
这个web爬虫需要用到python的requests, beautifulsoup, selenium这几个库。
因为selenium需要基于浏览器来操作,因此我们需要安装相应的driver。Chrome, Firefox都有对应的driver。因为我是用的firefox,因此在这个网址下载Firefox的driver, Releases · mozilla/geckodriver · GitHub
之后我们可以调用selenium来加载网站了,如以下代码:
- from selenium.webdriver.firefox.service import Service
- from selenium.webdriver.firefox.options import Options
- from selenium.webdriver.common.by import By
- from selenium import webdriver
- import time
-
- options = Options()
- options.binary_location = r'C:\Program Files\Mozilla Firefox\firefox.exe'
- options.add_argument("--headless")
- options.add_argument("--no-sandbox")
- service = Service(executable_path="c:/software/geckodriver.exe")
- browser = webdriver.Firefox(service=service, options=options)
- browser.get("https://blog.csdn.net/gzroy?type=blog")
代码中的options设置了--headless的参数,表示不会打开一个浏览器的窗口,如果想观看selenium操作浏览器的状态,可以把这个参数设置取消。等待浏览器加载网页完毕之后,我们就可以读取文章的列表以及网址了:
- articles = []
- articles_num = 0
- while True:
- elements = browser.find_elements(By.TAG_NAME, 'a')
- for item in elements:
- href = item.get_attribute("href")
- if type(href) is str:
- if href.startswith("https://blog.csdn.net/gzroy/article/details") and href not in articles:
- articles.append(href)
- if len(articles)<=articles_num:
- break
- if articles_num==0:
- browser.execute_script('window.scrollTo(0,document.body.scrollHeight/2)')
- time.sleep(0.5)
- articles_num = len(articles)
- browser.execute_script('window.scrollTo(0,document.body.scrollHeight)')
- time.sleep(2)
因为CSDN的文章列表不会一次全部加载,当滚动页面时候才会陆续加载,因此我们需要执行Javascript的语句,模拟滚动到页面下方。另外有一个奇怪的地方,就是如果第一次滚动到页面下方,好像页面并没有自动记载隐藏的文章,因此我改动了一下,第一次先滚动到页面中间,然后再滚动到页面最下方,这样就可以了。可能是和网站的一些具体设定相关。
获取到文章列表之后,我们就可以依次访问每篇文章,读取文章内容并保存到数据库中。
我这里选取了sqlite3这个轻量级的数据库,用requests来获取网页内容,用beautifulsoup来解析网页,提取文章的标题,创建时间和内容。
首先是访问数据库,创建一个数据表用于保存文章,代码如下:
- conn = sqlite3.connect('blog.db')
- c = conn.cursor()
- c.execute('''CREATE TABLE ARTICLE
- (ID INT PRIMARY KEY NOT NULL,
- TITLE TEXT NOT NULL,
- CREATETIME TEXT NOT NULL,
- CONTENT TEXT);''')
- conn.commit()
然后是构建一个循环,每次访问文章列表的一篇文章,提取相关内容并保存到数据库:
- id = 0
- for item in articles[::-1]:
- article = requests.get(item, headers = {'User-Agent':'Mozilla/5.0'})
- soup = BeautifulSoup(article.text, 'html.parser')
- title = soup.find('h1', {'id': 'articleContentId'}).text
- title_b64 = base64.b64encode(title.encode()).decode()
- content = soup.find('div', {'id':'content_views'}).encode_contents()
- content_b64 = base64.b64encode(content).decode()
- createTime = soup.find('span', {'class':'time'}).text[2:-3]
- sqlstr = "INSERT INTO ARTICLE (ID,TITLE,CREATETIME,CONTENT) VALUES (" + \
- str(id) + ",'" + title_b64 + "','" + createTime + "','" + content_b64 + "')"
- c.execute(sqlstr)
- id += 1
- conn.commit()
- conn.close()
这里我提取了文章的标题和内容正文之后,先做了一个base64的转换再保存到数据库,这里主要是考虑避免一些特殊字符对sql语句的影响。
至此,整个爬虫已经处理完毕所有的文章了。下一步我将构建一个Blog,把我们保存的文章展示在Blob中。待续。。。