本系统的这部分内容好像没什么好写的,就不从Scrapy基础开始说了,挑一些重点部分和容易出错的地方

来写一下。其中前程无忧和智联招聘用的是scrapy,拉勾网因为反爬太强了,用的是selenium,只能降低采集效率,用的是用selenium模拟登录,并且还得手动输入验证码(九宫格的验证码难以识别,找了好几个平台联系客服都说无法识别这种,就没怎么继续找了,虽然手动比较low)

1,对与用Scrapy爬取前程无忧和智联招聘的具体的过程就省略了。我爬的是这两个招聘网站中的IT岗位信息,前期没有设计好,导致爬虫数量很多,想要很好的入库就得用异步插入的方式,因为scrapy是Twisted异步框架,如果使用传统的pymysql,commit插入方式就很有可能导致入库不完整的情况,因为scrapy的采集速度要远远大于同步插入的速度,所以,也应该使用异步插入的方式来保存数据,具体方法如下:

导入twisted:

import MySQLdb
from twisted.enterprise import adbapi
import MySQLdb.cursors

定义MysqlTwistedPipline类:

class MysqlTwistedPipline(object):
    def __init__(self, dbpool):
        self.dbpool = dbpool

    @classmethod
    def from_settings(cls, settings):
        dbparms = dict(
            host=settings["MYSQL_HOST"],
            db=settings["MYSQL_DBNAME"],
            user=settings["MYSQL_USER"],
            passwd=settings["MYSQL_PASSWORD"],
            charset='utf8',
            cursorclass=MySQLdb.cursors.DictCursor,
            use_unicode=True,
        )
        dbpool = adbapi.ConnectionPool("MySQLdb", **dbparms)

        return cls(dbpool)

根据不同爬虫名字来执行不同的插入语句:

def process_item(self, item, spider):
    # 使用twisted将mysql插入变成异步执行
    if spider.name == 'qc_java' or spider.name == 'zl_java':
        query = self.dbpool.runInteraction(self.do_insert_java, item)
        query.addErrback(self.handle_error, item, spider)  # 处理异常
    elif spider.name == 'qc_python' or spider.name == 'zl_python':
        query = self.dbpool.runInteraction(self.do_insert_python, item)
        query.addErrback(self.handle_error, item, spider)
    elif spider.name == 'qc_golang' or spider.name == 'zl_golang':
        query = self.dbpool.runInteraction(self.do_insert_golang, item)
        query.addErrback(self.handle_error, item, spider)
    elif spider.name == 'qc_cplus' or spider.name == 'zl_cplus':
        query = self.dbpool.runInteraction(self.do_insert_cplus, item)
        query.addErrback(self.handle_error, item, spider)
    elif spider.name == 'qc_bigdata' or spider.name == 'zl_bigdata':
        query = self.dbpool.runInteraction(self.do_insert_bigdata, item)
        query.addErrback(self.handle_error, item, spider)
    elif spider.name == 'qc_arithmetic' or spider.name == 'zl_arithmetic':
        query = self.dbpool.runInteraction(self.do_insert_arithmetic, item)
        query.addErrback(self.handle_error, item, spider)
    elif spider.name == 'qc_ai' or spider.name == 'zl_ai':
        query = self.dbpool.runInteraction(self.do_insert_ai, item)

def handle_error(self, failure, item, spider):
    print(failure)

具体mysql插入语句:

def do_insert_java(self, cursor, item):
    insert_sql = "insert into  `zp_java` (where_from,url,url_obj_id,job_name,company_name,salary_min,salary_max,job_city,experience_year,education_need,publish_date,job_advantage_tags,position_info,job_classification,crawl_time) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
    item['url_obj_id'] = item['url_obj_id'] + "{0}".format(random.randint(61, 70))
    cursor.execute(insert_sql,
                   (item["where_from"], item["url"], item["url_obj_id"], item["job_name"], item["company_name"], item["salary_min"], item["salary_max"],
                    item["job_city"], item["experience_year"], item["education_need"], item["publish_date"],
                    item["job_advantage_tags"], item["position_info"], item["job_classification"],
                    item["crawl_time"]))

2,使用Selenium模拟登陆拉钩代码:

try:
    self.driver.get(self.login_url)
    self.driver.find_element_by_css_selector("div:nth-child(2) > form > div:nth-child(1) > input").send_keys(
        self.username)
    time.sleep(3)
    self.driver.find_element_by_css_selector("div:nth-child(2) > form > div:nth-child(2) > input").send_keys(
        self.password)
    time.sleep(4)
    self.driver.find_element_by_css_selector(
        "div:nth-child(2) > form > div.input_item.btn_group.clearfix > input").click()
    time.sleep(2)

   将拉勾网采集的数据一致遇到一个bug,就是字符串转义的问题,因为采集的字段有岗位详情描述,这是一个longtext,里面夹着一些特殊符号就会才入库的时候出现报错,要pymysql.escape_string()就可以很好的解决,这个函数是pymysql自带的。

 

效果截图:

基于Scrapy的数据分析可视系统 之 数据采集

相关文章: