爬虫实战——简书文章爬取(selenium+Chrome)

引言

本次爬虫使用了selenium,结合Chrome浏览器进行页面爬取。数据存储用的是MySQL数据库,个人感觉用MongoDB更好一些,但是最近在学MySQL数据库,所以就果断用它了。

思路分析

起始URL:https://www.jianshu.com/
思路比较简单,就是先访问起始URL(简书的主页),再找到文章的URL,打开该URL,爬取想要文章的信息即可。思路虽然简单,但是我却遇到了不少的问题,最大的问题就是,如果你只是打开简书的主页而不滚动滚动条,页面中文章的URL是有限的,也就是说只能爬取页面中文章的URL,要想出现更多的文章必须要滚动滚动条,我的处理方法时,写一条js代码,当页面的URL都爬完后,执行一次js代码,让滚动条到达页面的底部。

window.scrollTo(0,document.body.scrollHeight)

但是,在多次滚动滚动条后,会出现阅读更多的按钮,此时再滚动滚动条就已经没有用了,所以,要找到这个按钮并且模拟点击。

完整代码

# !/usr/bin/env python
# —*— coding: utf-8 —*—
# @Time:    2020/2/5 20:21
# @Author:  Martin
# @File:    jianshu.py
# @Software:PyCharm
from selenium import webdriver
from lxml import etree
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
import pymysql


class JianshuSpider(object):
    driver_path = r'./chromedriver.exe'
    # 爬取的文章数目
    article_num = 50
    # 文章索引
    article_index = 1
    url_set = set()

    def __init__(self):
        self.driver = webdriver.Chrome(executable_path=JianshuSpider.driver_path)
        self.url = 'https://www.jianshu.com'
        self.conn = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',
            password='root',
            database='jianshu',
            charset='utf8mb4'
        )
        self.cursor = self.conn.cursor()

    def run(self):
        js_code = 'window.scrollTo(0,document.body.scrollHeight)'
        self.driver.get(self.url)
        self.driver.execute_script(js_code)
        self.driver.execute_script(js_code)
        source = self.driver.page_source
        self.parse_page_list(source)
        while True:
            self.driver.execute_script(js_code)
            try:
                btn = self.driver.find_element_by_class_name("load-more")
                btn.click()
            except :
                self.driver.execute_script(js_code)
                self.driver.execute_script(js_code)
            source = self.driver.page_source
            self.parse_page_list(source)
            if self.article_index > self.article_num:
                break

    def parse_page_list(self, source):
        html = etree.HTML(source)
        li_list = html.xpath('//ul[@class="note-list"]/li')
        for li in li_list:
            url = self.url + li.xpath('./div/a/@href')[0]
            if url not in self.url_set:
                self.parse_detail_page(url)
                self.url_set.add(url)
            time.sleep(1)

    def parse_detail_page(self, url):
        js_ = 'window.open("%s")' % url
        self.driver.execute_script(js_)
        self.driver.switch_to.window(self.driver.window_handles[1])
        WebDriverWait(driver=self.driver, timeout=10).until(
            EC.presence_of_element_located((By.XPATH, '//h1[@class="_1RuRku"]'))
        )
        source = self.driver.page_source
        html = etree.HTML(source)
        title = html.xpath('//h1[@class="_1RuRku"]/text()')[0]
        author = html.xpath('//span[@class="FxYr8x"]/a/text()')[0]
        avatar = html.xpath('//div[@class="_2mYfmT"]/a/img/@src')[0]
        public_time = html.xpath('//div[@class="s-dsoj"]/time/text()')[0]
        p_list = html.xpath('//article[@class="_2rhmJa"]/p')
        content = ""
        for p in p_list:
            text = p.xpath('./text()')
            content += "".join(text)
        data = [title, author, avatar, public_time, content]
        print(self.article_index, data)
        self.save(data)
        self.article_index += 1
        self.driver.close()
        self.driver.switch_to.window(self.driver.window_handles[0])

    def save(self, data):
        sql = 'insert into article(title,author,avatar,public_time, content) values(%s,%s,%s,%s,%s);'
        self.cursor.execute(sql, (data[0], data[1], data[2], data[3], data[4]))
        self.conn.commit()

    def close(self):
        self.cursor.close()
        self.conn.close()
        self.driver.close()


if __name__ == '__main__':
    spider = JianshuSpider()
    spider.run()
    spider.close()

总结分析

爬取页面的效率比较低,有的时候会在一个页面停留很久。在判断一个文章的URL是否已经爬过时,我用的方法是,将爬取过的URL放到一个集合中,当有新的URL时,就判断新的URL是否在这个集合中,如果在集合中,就证明已经爬取过了,如果没在集合中,就爬取该URL,并将其加入集合。不知道有没有更好的方法,如果有的话,烦请大佬们在文章底部评论告诉我,在此我先行谢过了。


在这里插入图片描述

发布了151 篇原创文章 · 获赞 236 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Deep___Learning/article/details/104207040