クローラーによってクロールされるページは、JD.com の電子書籍 Web サイトのページで、毎日いくつかの無料電子書籍が更新されます。クローラーは、毎日更新される無料書籍のタイトルをできるだけ早く電子メールで送信します。
私は少し前に Python を独学で勉強しました。初心者なので、練習用に何か書いてみようと思いました。Python でクローラー スクリプトを書くのがとても便利であることを最近知りました。 MongoDB 必要なのは東風だけです。
クローラーによってクロールされるページは、JD.com の電子書籍 Web サイトのページであり、クローラーは無料の電子書籍を送信します。書籍のタイトルは毎日電子メールで更新されます。できるだけ早く私に送信して、ダウンロードするよう通知してください。
1. アイデアの作成:
1. クローラー スクリプトはその日の無料書籍情報を取得します
2. 取得した書籍情報をデータベース内の情報を比較します。ブックが存在する場合は何も実行しません。ブックが存在しない場合は、データベースへの挿入操作を実行し、データ情報を MongoDB
に保存します。データベース挿入操作を実行するときに、更新されたデータをメールとして送信します
4. APScheduler スケジューリング フレームワークを使用して、Python スクリプトのスケジューリングを完了します
2. 主な知識スクリプトのポイント:
1.python シンプルクローラー
今回ページをクロールするために使用するモジュールは urllib2 インポートされたモジュールは次のとおりです:
import urllib2 from sgmllib import SGMLParser
urlopen() このメソッドは、コンテンツに保存されている Web ページの HTML ソース コードを取得します。 listhref() クラスの主な機能は、HTML コードを解析することです。 HTML タイプの半構造化ドキュメントを処理します。
content = urllib2.urlopen('http://sale.jd.com/act/yufbrhZtjx6JTV.html').read() listhref = ListHref() listhref.feed(content)
listhref() コードは、以下のすべてのコードにあります。ここでは、いくつかの重要なポイントを示します。 () クラスは SGMLParser クラスを継承し、その内部メソッドをオーバーライドします。 SGMLParser は、HTML を開始タグや終了タグなどの有用な部分に分割します。データの一部を有用な部分に正常に分割すると、見つかったデータに基づいて独自の内部メソッドの 1 つを呼び出します。このパーサーを使用するには、SGMLParser クラスをサブクラス化し、親クラスのこれらのメソッドをオーバーライドする必要があります。
SGMLParser は、HTML をさまざまなタイプのデータとタグに解析し、タイプごとに個別のメソッドを呼び出します。
開始タグ (Start_tag)は、07e6e06e0dc95dc83bb70d14dca11cbe のようなブロックを開始する HTML タグです。 ;、
、、など、または <br> や <img alt="Python は Web クローラー スクリプトを作成し、APScheduler スケジューリングを実装します。" > などの固有のタグ。この例では、開始タグ 3499910bf9dac5ae3c52d5ede7383485 を見つけると、SGMLParser は start_a または do_a という名前のメソッドを探します。見つかった場合、SGMLParser はタグの属性リストを使用してこのメソッドを呼び出し、それ以外の場合は、タグの名前と属性リストを使用して、unknown_starttag メソッドを呼び出します。 <br>終了タグ (End_tag) <br> は、73a6ac4ed44ffec12cee46588e518a5e、9c3bca370b5104690d9ef395f2c5f8d1、36cc49f0c466276486e50c850b7e4956、bc5574f69a0cba105bc93bd3dc13c4ec などのブロックを終了する HTML タグです。この例では、終了タグが見つかると、SGMLParser は end_a という名前のメソッドを探します。見つかった場合、SGMLParser はこのメソッドを呼び出します。見つかった場合は、タグの名前を指定してunknown_endtagを呼び出します。 <br>テキスト データ<br> テキスト ブロックを取得します。他のカテゴリのマークが満たされない場合、handle_data が呼び出されてテキストを取得します。 <br><br>この記事では次のカテゴリは使用されません文字参照 (文字参照)<p>文字の 10 進数または同等の 16 進数で表されるエスケープ文字。文字が見つかると、SGMLParser は handle_charref を呼び出します。文字。 <br>エンティティ参照 (Entity Reference) <br>HTML エンティティ (&ref と同様) エンティティが見つかると、SGMLParser はエンティティの名前を指定して handle_entityref を呼び出します。 <br>コメント <br>HTML コメント。a69de9cf48008bc5997724f3266c029c の間に含まれます。見つかった場合、SGMLParser はコメントの内容を指定して handle_comment を呼び出します。 <br>処理命令 <br>HTML 処理命令。9f23c477ccd59b80f2f909dd569e778c の間に含まれます。見つかった場合、SGMLParser はコマンドの内容を使用して handle_pi を呼び出します。 <br>宣言<br>3fddbc1056c10caaf8ceb37d60d3a8e0 の間に含まれる DOCTYPE などの HTML 宣言。見つかった場合、SGMLParser は宣言内容を使用して handle_decl を呼び出します。 <br><br>具体的な手順については、API を参照してください: http://www.php.cn/</p><p></p>2. Python は MongoDB データベースを操作します <p><strong></strong>まず、Pythonをインストールします mongoDBドライバーPyMongoの場合は、ダウンロードアドレス: http://www.php.cn/</p><p>インポートモジュール</p><p></p><p class="jb51code"></p><pre class="brush:py;">import pymongo
データベース サーバー 127.0.0.1 に接続し、データベース mydatabase
mongoCon=pymongo.Connection(host="127.0.0.1",port=27017) db= mongoCon.mydatabase
に切り替えて、データベースに関連する書籍情報を検索します。書籍はコレクションです
bookInfo = db.book.find_one({"href":bookItem.href})
Python は中国語をサポートしていますが、中国語のエンコードとデコードはまだ比較的複雑です。 http:/ を参照してください。関連するデコードとエンコードについては /www.php.cn/ を参照してください。
b={ "bookname":bookItem.bookname.decode('gbk').encode('utf8'), "href":bookItem.href, "date":bookItem.date } db.book.insert(b,safe=True)
PyMongo については、API ドキュメント http://www を参照してください。 .php.cn/
3.python がメールを送信しましたメール モジュールをインポートします
# Import smtplib for the actual sending function import smtplib from email.mime.text import MIMEText
「localhost」はメールサーバーのアドレスです
msg = MIMEText(context) #文本邮件的内容
msg['Subject'] = sub #主题
msg['From'] = "my@vmail.cn" #发信人
msg['To'] = COMMASPACE.join(mailto_list) #收信人列表
def send_mail(mailto_list, sub, context): COMMASPACE = ',' mail_host = "localhost" me = "my@vmail.cn" # Create a text/plain message msg = MIMEText(context) msg['Subject'] = sub msg['From'] = "my@vmail.cn" msg['To'] = COMMASPACE.join(mailto_list) send_smtp = smtplib.SMTP(mail_host) send_smtp.sendmail(me, mailto_list, msg.as_string()) send_smtp.close()
应用文档:http://www.php.cn/
4.Python调度框架ApScheduler
下载地址http://www.php.cn/
官方文档:http://www.php.cn/
API:http://www.php.cn/
安装方法:下载之后解压缩,然后执行python setup.py install,导入模块
from apscheduler.scheduler import Scheduler
ApScheduler配置比较简单,本例中只用到了add_interval_job方法,在每间隔一段时间后执行任务脚本,本例中的间隔是30分钟。可参考实例文章http://www.php.cn/
# Start the scheduler sched = Scheduler() sched.daemonic = False sched.add_interval_job(job,minutes=30) sched.start()
关于daemonic参数:
apscheduler会创建一个线程,这个线程默认是daemon=True,也就是默认的是线程守护的。
在上面的代码里面,要是不加上sched.daemonic=False的话,这个脚本就不会按时间运行。
因为脚本要是没有sched.daemonic=False,它会创建一个守护线程。这个过程中,会创建scheduler的实例。但是由于脚本运行速度很快,主线程mainthread会马上结束,而此时定时任务的线程还没来得及执行,就跟随主线程结束而结束了。(守护线程和主线程之间的关系决定的)。要让脚本运行正常,必须设置该脚本为非守护线程。sched.daemonic=False
附:全部脚本代码
All Code
#-*- coding: UTF-8 -*- import urllib2 from sgmllib import SGMLParser import pymongo import time # Import smtplib for the actual sending function import smtplib from email.mime.text import MIMEText from apscheduler.scheduler import Scheduler #get freebook hrefs class ListHref(SGMLParser): def __init__(self): SGMLParser.__init__(self) self.is_a = "" self.name = [] self.freehref="" self.hrefs=[] def start_a(self, attrs): self.is_a = 1 href = [v for k, v in attrs if k == "href"] self.freehref=href[0] def end_a(self): self.is_a = "" def handle_data(self, text): if self.is_a == 1 and text.decode('utf8').encode('gbk')=="限时免费": self.hrefs.append(self.freehref) #get freebook Info class FreeBook(SGMLParser): def __init__(self): SGMLParser.__init__(self) self.is_title="" self.name = "" def start_title(self, attrs): self.is_title = 1 def end_title(self): self.is_title = "" def handle_data(self, text): if self.is_title == 1: self.name=text #Mongo Store Module class freeBookMod: def __init__(self, date, bookname ,href): self.date=date self.bookname=bookname self.href=href def get_book(bookList): content = urllib2.urlopen('http://sale.jd.com/act/yufbrhZtjx6JTV.html').read() listhref = ListHref() listhref.feed(content) for href in listhref.hrefs: content = urllib2.urlopen(str(href)).read() listbook=FreeBook() listbook.feed(content) name = listbook.name n= name.index('》') #print (name[0:n+2]) freebook=freeBookMod(time.strftime('%Y-%m-%d',time.localtime(time.time())),name[0:n+2],href) bookList.append(freebook) return bookList def record_book(bookList,context,isSendMail): # DataBase Operation mongoCon=pymongo.Connection(host="127.0.0.1",port=27017) db= mongoCon.mydatabase for bookItem in bookList: bookInfo = db.book.find_one({"href":bookItem.href}) if not bookInfo: b={ "bookname":bookItem.bookname.decode('gbk').encode('utf8'), "href":bookItem.href, "date":bookItem.date } db.book.insert(b,safe=True) isSendMail=True context=context+bookItem.bookname.decode('gbk').encode('utf8')+',' return context,isSendMail #Send Message def send_mail(mailto_list, sub, context): COMMASPACE = ',' mail_host = "localhost" me = "my@vmail.cn" # Create a text/plain message msg = MIMEText(context) msg['Subject'] = sub msg['From'] = "my@vmail.cn" msg['To'] = COMMASPACE.join(mailto_list) send_smtp = smtplib.SMTP(mail_host) send_smtp.sendmail(me, mailto_list, msg.as_string()) send_smtp.close() #Main job for scheduler def job(): bookList=[] isSendMail=False; context="Today free books are" mailto_list=["mailto@mail.cn"] bookList=get_book(bookList) context,isSendMail=record_book(bookList,context,isSendMail) if isSendMail==True: send_mail(mailto_list,"Free Book is Update",context) if __name__=="__main__": # Start the scheduler sched = Scheduler() sched.daemonic = False sched.add_interval_job(job,minutes=30) sched.start()