本文目标:
上篇我们获得了评论用户ID及主页地址。本篇就可以基于这些数据进行一些数据分析和市场操作。理论上学会了本文的方法,你可以在任何一个网页发送广告信息,本文具有被坏人利用的可能性,因此设置了收费,而这一套爬虫教程,如果在网易云课堂找网课教,学费要1200元左右。网课的暴利还是巨大的。终极目标达成:
1、通过热门歌手,抓取歌曲ID。
2、通过歌曲ID,抓取评论用户ID。
3、通过评论用户ID,发送定向推送消息。
上两篇完成了步骤1、步骤2,本文完成步骤3.
总结篇:requests和selenium的区别:requests无页面的方法获取歌曲ID,速度比较快,但是只能获取一些无需登录的公开网页,如果需要用户登录和验证,requests将无法做到。
selenium的优势在于完全模仿人打开网页的操作,就好像你雇佣了一个助手帮你做事一样,非常直观,也不会被禁止访问。而且对于需要用户登录的界面(如微博等),用selenium能轻松跳过验证的麻烦环节。
上篇我们用MYSQL存储爬取用户的主页信息,本篇将支持错误重做,每处理完一条记录就打一个处理标志位Y,和我们生产系统的做法类似。
步骤1:查询用户lD和主页的表
这里需要查询userinf的表,获取存储的用户的ID和主页地址。我们需要创建一个python程序来插入这个表。
python程序命名为:getUserURLSQL.py,代码为:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'luoji'
import pymysql
# from ,where, group by, select, having, order by, limit
class Mysql_pq(object):
def __init__(self):
self.conn = pymysql.Connect(host='127.0.0.1',
port=3306,
user='root',
passwd='root',
db='python',
#创建数据库格式时用utf8mb4这个格式,因为可以存储表情等非字符
charset='utf8mb4'
)
self.cursor = self.conn.cursor()
def __del__(self):
self.cursor.close()
self.conn.close()
def select_userinf(id_start=141,id_end=145):
helper = Mysql_pq()
print('连接上了数据库python,准备插入歌曲信息')
user_id_list ,user_name_list,user_url_list= [],[],[]
sql = "select distinct(user_id) , user_name ,user_url from userinf WHERE clbz = 'N' and id>= %s and id <= %s" %(id_start,id_end)
print('sql is :',sql)
helper.cursor.execute(sql)
results = helper.cursor.fetchall()
for row in results:
user_id = row[0]
user_name = row[1]
user_url = row[2]
# 打印结果
print('user_id =', user_id)
print('user_name =',user_name)
user_id_list.append(user_id)
user_name_list.append(user_name)
user_url_list.append(user_url)
helper.cursor.close()
return user_id_list,user_name_list,user_url_list
if __name__ == '__main__':
user_id_list,user_name_list,user_url_list = select_userinf(id_start=141,id_end=145)
print('user_id_list = ',user_id_list )
print('user_url_list = ', user_name_list)
print('user_url_list = ', user_url_list)
print('test over')
支持错误重做:回头更新userinf表
为了错误重做,我们处理完一条userinf就更新处理标志为Y,当出错时,程序自动跳过处理标志位Y的记录,仅仅处理处理标志位N的记录,这样就可以完成接力。
所以为了完成这个接力,我们需要在处理完一个评论用户后,回头更新userinf。我们需要创建一个python程序来插入这个表。
python程序命名为:updateUserInfSQL.py,代码为:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'luoji'
import pymysql
# from ,where, group by, select, having, order by, limit
class Mysql_pq(object):
def __init__(self):
self.conn = pymysql.Connect(host='127.0.0.1',
port=3306,
user='root',
passwd='root',
db='python',
#创建数据库格式时用utf8mb4这个格式,因为可以存储表情等非字符
charset='utf8mb4'
)
self.cursor = self.conn.cursor()
def __del__(self):
self.cursor.close()
self.conn.close()
def update_userinf(user_id):
helper = Mysql_pq()
print('连接上了数据库python,准备插入歌曲信息')
sql = "UPDATE userinf SET clbz = 'Y' WHERE user_id= '%s'" % (user_id)
print('sql is :', sql)
helper.cursor.execute(sql)
helper.conn.commit()
if __name__ == '__main__':
user_id = '124956415'
update_userinf(user_id)
print('user_id = ',user_id)
print('update user_id %s over' %(user_id))
定向发送消息给用户:
为了顺利跳过网页登录验证,我们本次使用selenium自动化控制模块来控制浏览器访问,这样服务器无法区分是爬虫还是用户的访问,而且用户仅需要登录一次即可。
登录这里也是有技巧的,网上很多用户想把登录也自动化,搞得程序异常复杂,因为要破解验证信息,何苦了?就像:明明到小卖部买瓶矿泉水可以喝一天,你非要证明自己聪明去找两份氢气(H2)和一份氧气(O2)来燃烧,来产生水(H2O)来喝。
具体怎么做呢?暂时保密。嘿嘿。私信、留言可得。
我们需要创建一个python程序来发送消息。
代码为:
import re
import time
import numpy as np
from flask_cors.core import LOG
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver import ChromeOptions
from getUserURLSQL import *
from updateUserInfSQL import *
def sendMessage(user_id_list,user_name_list,user_url_list):
# 如果driver没加入环境变量中,那么就需要明确指定其路径
# 验证于2021年2月21日
# 直接
# chrome_options = ChromeOptions()
# chrome_options.add_argument('--headless')
# chrome_options.add_argument('--no-sandbox')
# driver = webdriver.Chrome('/root/qk_python/python/data/collect/weibo_spider/priv/chromedriver',
# chrome_options=chrome_options)
driver = webdriver.Firefox()
#driver = webdriver.Chrome()
driver.maximize_window()
driver.set_page_load_timeout(30)
driver.set_window_size(1124, 850)
url = 'https://music.163.com/#/user/home?id=1766013257' #初始化页面看,用于用户登录
driver.get(url)
print('请登录个人网易云账号。')
time.sleep(10) #等待登录时间
for user_id,user_name,user_url in zip(user_id_list,user_name_list,user_url_list):
print('now the url is :',user_url)
driver.get(user_url)
time.sleep(3)
print('开始准备发消息')
driver.switch_to.frame('g_iframe') # 网易云的音乐元素都放在框架内!!!!先切换框架
print('准备点击私信')
href_xpath = "//div[contains(@class,'g-wrap p-prf')]//div[contains(@class,'name f-cb')]//a[contains(@class,'btn u-btn u-btn-7 f-tdn')]"
submit = driver.find_element_by_xpath(href_xpath)
print('定位私信成功')
ActionChains(driver).double_click(submit).perform()
ActionChains(driver).click(submit).perform()
time.sleep(2)
text_xpath = "//div[contains(@class,'item f-cb')]//div[contains(@class,'ct j-flag')]//div[contains(@class,'u-txtwrap f-pr')]//textarea[contains(@class,'u-txt area j-flag')]"
text_field = driver.find_element_by_xpath(text_xpath)
print('清空输入框')
text_field.clear()
message = user_name +',祝你新年快乐。2021天天开心。' #私信内容
text_field.send_keys(message)
#点击发送信息
send_xpath = "//div[contains(@class,'item f-cb')]//div[contains(@class,'ct j-flag')]//div[contains(@class,'btns f-cb f-pr')]//a[contains(@class,'f-fr u-btn u-btn-1 j-flag')]"
send_buttom = driver.find_element_by_xpath(send_xpath)
print('定位到了发送按钮')
ActionChains(driver).click(send_buttom).perform()
print('发送完毕')
time.sleep(1) #等待一个发送延迟时间
update_userinf(user_id) #标记用户状态为已发送,支持错误重做。
print('user_id = %s is updated ,准备下一个用户.' %(user_id))
if __name__ == '__main__':
id_start, id_end = 145, 148 #定义查询用户的范围,以便于做到多进程并行发送。每个程序查询一部分ID范围的用户
user_id_list,user_name_list,user_url_list = select_userinf(id_start, id_end) #获取用户信息
sendMessage(user_id_list,user_name_list,user_url_list) #发送消息
发送时的结果如下:
这里有几点说明:
1、 userinf中用户的id是个自增的数,可以用来做多进程并发控制,每个进程读取一段id段。加快发送速度。
2、每个进程的浏览器相互不会干扰,不会串。
至此,学完这3个步骤,你就具备向10w级别的用户发消息了。省了1200元的学费,岂不痛快哉!!!