Python使用selenium爬取百度搜索

主要实现方法:通过selenium的webdriver模拟浏览器点击下一页,使用正则表达式获取该页的页数,然后把页数保存至本地CSV文件,暂停之后再运行,读取本地CSV文件的指针指向的最后一个数据即为开始爬取的页数。
代码注释比较多,如下:

from selenium import webdriver
import csv
import threading
import time
from lxml import etree
from queue import Queue
import re


class BaiduSpider(object):
    def __init__(self):
        self.url = 'https://www.baidu.com/'
        self.page_num = self.read_page_num()
        self.driver = webdriver.Chrome()
        self.q = Queue()

    # 读取最后爬取过的页数
    def read_page_num(self):
        with open('已爬取URL.csv', 'r') as f:
            f = csv.reader(f)
            page_num = list(f)[-1][0]
            print(page_num)
        return page_num

    # 获取首页
    def get_first_page(self):
        self.driver.get(self.url)
        self.driver.find_element_by_name('wd').send_keys('注册页面')
        self.driver.find_element_by_id('su').click()
        time.sleep(3)
        self.click_next_page()

    # 解析页面
    def parse_page(self):
        response = self.driver.page_source
        html = etree.HTML(response)
        hrefs = html.xpath('//div[@class="result c-container "]/h3[@class="t"]/a/@href')
        flag = html.xpath('//div[@id="page"]/a[last()]/@class')[0]
        return flag, hrefs

    # 将已爬取的页数写入本地
    def save_page_num(self):
        url = self.driver.current_url
        page_num = re.search('&pn=(\d+)', url)
        with open('已爬取URL.csv', 'a', newline='') as f:
            w = csv.writer(f)
            w.writerow([page_num.group(1)])

    # 点击下一页, 感觉显示、隐式等待是个摆设,所以自己封装了个等待。
    # 其实可以使用retring模块,重发几次再报错休眠,人为处理
    def click_next_page(self):
        try:
            self.driver.find_element_by_xpath('//div[@id="page"]/a[last()]').click()
        except:
            time.sleep(10)
            self.driver.find_element_by_xpath('//div[@id="page"]/a[last()]').click()

    # 获取每一页数据, 开趴.
    def get_page_html(self):
        self.get_first_page()
        while True:
            # 判断每一页URL是否已经爬取,已爬取则不解析直接跳转一页
            page_url = self.driver.current_url
            page_num = re.search('&pn=(\d+)', page_url)
            print(page_num.group(1), self.page_num)
            # 判断当前页数是否大于已爬取的页数
            if page_num.group(1) > self.page_num:
                # 解析页面数据,判定是否到达末页,以及获取详情页的URL
                flag, urls = self.parse_page()
                # 判断是否为末页
                if flag != 'n':
                    print('已爬取百度全部数据')
                    break
                # 将详情页URL加入队列
                for url in urls:
                    self.q.put(url)
                # 将当前页面URL的页数保存至本地
                self.save_page_num()
                # 跳转至下一页 不想写显示等待,网不太好感觉还是会报错
                time.sleep(3)
                self.click_next_page()
            else:
                # 如果当前页数不大于已爬取页数,则点击下一页
                self.click_next_page()

    # 获取详情页
    def get_detail_html(self):
        while True:
            if self.q.qsize() != 0:
                url = self.q.get()
                print(url)
            else:
                time.sleep(5)

    def run(self):
        # 获取每页URL
        c = threading.Thread(target=self.get_page_html)
        c.start()
        # 解析详情页
        t = threading.Thread(target=self.get_detail_html)
        t.start()


if __name__ == '__main__':
    zhuce = BaiduSpider()
    zhuce.run()

运行效果如下:

Python使用selenium爬取百度搜索_第1张图片
有个不好的地方,就是如果停止爬取之后再来爬取,需要等待driver一直点击下一页,直到我们需要的那一页再开始请求和解析详情页的数据。如果像百度这样的网站,上千万的数据量太大,要给他爬完,这个肯定是不行的,不过适合爬取小说,电影等有更新的网站,原理基本一样
Python使用selenium爬取百度搜索_第2张图片

你可能感兴趣的:(Python爬虫,selenium,百度,csv,xpath,ajax)